Java, Teil 2 – Grafische Programmierung mit Swing

Posted in Uncategorized on Dezember 7, 2009 by echofalko

Dieser Artikel soll über die Möglichkeiten der Entwicklung grafischer Anwendungen mit der Swing-Bibliothek [1] informieren, Anfängern eine Starthilfe geben und Kenner zumindest mit Hintergrundinformationen versorgen.

Redaktioneller Hinweis: Es empfiehlt sich, den ersten Teil dieses Artikels („Java, Teil 1 – Einführung in eine moderne Sprache“, freiesMagazin 10/2009 [2]) nachzulesen, falls die Grundlagen von Java noch nicht verinnerlicht sind.

Swing – Was ist das?

Bei Swing handelt es sich um eine vorprogrammierte Klassenbibliothek, mit deren Hilfe grafische Anwendungen unter Java entwickelt werden können. Es ist also nicht erforderlich zu definieren, was ein Fenster oder was ein Textfeld ist und wie sich solche Elemente verhalten können. Sie werden einfach „benutzt“, in dem ein Objekt erzeugt wird, das beispielsweise vom Typ „Fenster“ ist. Ungeduldige können sich bei Sun direkt die vielen vordefinierten Elemente ansehen [3].

Vorbereitung

Es sollte auf eine Entwicklungsumgebung zurückgegriffen werden, um die Vorzüge der automatischen Vervollständigung und der Syntaxprüfung zu genießen. So lassen sich Tippfehler sehr leicht aufspüren. Wie im ersten Teil bereits erläutert, bieten sich für die in diesem Artikel beschriebenen Zwecke besonders Netbeans und Eclipse an, die beide frei und gleichberechtigt sind.

In diesem Artikel wird aber die Einrichtung von Eclipse beschrieben. Bei vielen Distributionen kann das Paket eclipse installiert werden oder direkt die binären Dateien der aktuellen Version von der Homepage [4] heruntergeladen werden.

Eclipse in Action

Es handelt sich um einen Ordner, in dem die Startdatei direkt ausführbar ist. Dieser wird dann zum Beispiel mit root-Rechten in das Verzeichnis /opt verschoben. Einen Starter im Menü muss man dann allerdings manuell angelegen. Beim ersten Starten erscheint die Aufforderung, einen Workspace anzulegen. Das ist das Verzeichnis, in dem alle relevanten Dateien der Projekte abgelegt werden.

Sollte sich in diesem Fenster bereits Eclipse beschweren, dass lediglich eine „gij“-Version von Java gefunden wurde, könnten Fehler auftreten, da diese Version nicht offiziell von Eclipse unterstützt wird. Keine Probleme treten auf, wenn das offizielle sun-java6-jdk und die sun-java6-jre installiert sind. Eine „openjdk“-Variante tut es aber auch, falls großer Wert auf freie Lizenzen gelegt wird. Mit dem Befehl

$ java -version

kann geprüft werden, ob die Installation geglückt ist und auch erkannt wird. Sollte nicht die gewünschte Ausgabe erscheinen, kann es sein, dass mehrere Compiler und Laufzeitumgebungen parallel installiert sind. Da hilft meist die manuelle Einstellung durch den Befehl

# update-alternatives --config java

sofern das Alternativensystem [5] unter der benutzten Distribution verfügbar ist.

Nach Bestätigung des Pfades zum Workspace öffnet sich ein Begrüßungsbildschirm. Ist dieser oben rechts weggeklickt, öffnet sich zum ersten Mal die Java-Ansicht und die Programmierung kann beginnen. Es ist wichtig, die Dateien im Workspace nie direkt zu manipulieren, sondern nur über Eclipse. Ansonsten stimmen die Metadaten nicht mehr, und der Workspace kann zerstört werden.

Die Programmierung mit Swing

Zunächst muss ein neues Projekt erstellt werden. Dies gelingt unter „File » New » Java Project“. Nun wird dem Projekt noch ein Name gegeben (z. B. „SwingApp“) und gegebenenfalls die JRE eingestellt, zum Beispiel auf java-6-sun-1.6.0.16 oder welche JRE auch immer installiert ist. Der nächste Dialog kann ohne Änderungen bestätigt werden. Jetzt wird dem Projekt eine Klasse hinzugefügt, indem mit rechts auf das Projekt geklickt und „New » Class“ auswählt wird. Die Klasse wird in diesem Beispiel View gegannt, da sie eine grafische Oberfläche bereitstellen soll. Achtung: Klassennamen beginnen immer mit einem Großbuchstaben.

Wie werden nun Fenster mit Java erzeugt? Zunächst muss eine Instanz von JFrame erzeugt werden, welche das Hauptfenster darstellt. JFrame ist die gängigste Klasse, um ein Fenster mit Java zu erzeugen. Es werden bereits Grundfunktionen wie Fensterdekorationen bereitgestellt, ohne dies explizit zu programmieren. Bei Betrachtung des Quellcodes sollten alle Befehle problemlos nachvollziehbar sein:

public class View extends JFrame {
   View() {
       setSize(300, 300);
       setTitle("Minimal JFrame");
       setDefaultCloseOperation(EXIT_ON_CLOSE);
       setLocationRelativeTo(null);
       setVisible(true);
    }
}

View ist also direkt von JFrame abgeleitet. Das bedeutet, dass jede Instanz der Klasse View auch eine Instanz der Klasse JFrame ist. Im Konstruktor kann deshalb nun direkt die Größe und der Titel des Fensters festlegt werden, da die Klasse diese Variablen und Methoden von JFrame geerbt hat. Des Weiteren wird bestimmt, dass die Anwendung ordnungsgemäß beendet wird, sobald das Fenster geschlossen wird – ansonsten würde die Anwendung für immer als Hintergrundprozess weiterlaufen. Letztlich wird der Ort des Fensters in die Mitte des Bildschirms und das Fenster sichtbar gesetzt.

Netbeans in Action

Wenn der obige Quelltext einfach eingefügt wird, wird sich Eclipse beschweren, da die Klasse JFrame und deren Eigenschaften nicht bekannt sind. Durch Bewegung des Cursors hinter das Wort JFrame und Druck von „Strg“„Space“ wird die Umgebung angewiesen, automatisch den passenden Import hinzuzufügen. Sollte dies aus irgendwelchen Gründen nicht funktionieren, können für das Beispiel einfach

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

oben in die View Klasse als erste Zeilen eingefügt werden.

Die Klasse ist für sich allein nicht ausführbar, da sie keinen Einstiegspunkt hat, welcher immer die main-Methode sein muss. Es wird also noch eine Klasse hinzugefügt, etwa mit dem Namen Start. Aus Bequemlichkeit kann dabei das Häkchen „public static void main (String[]args)“ gesetzt werden und dieser Methodenkopf muss nicht mehr von Hand eingetippt werden. Die Klasse Start soll nichts anderes tun, als eine Instanz der Klasse View ohne Parameter zu erzeugen:

public class Start {
    public static void main(String[] args) {
        View myView = new View();
    }
}

Das Programm wird nun gestartet, indem die Klasse Start markiert und „Strg“„F11“ gedrückt wird. Es erscheint ein leeres Fenster mit der Größe 300×300 Pixel. In diesem könnten nun direkt weitere Elemente – dies ist erst seit neueren Versionen möglich – oder neue Container platziert werden, die wiederum atomare Elemente aufnehmen können. Als atomar werden Komponenten bezeichnet, die keine anderen Komponenten enthalten können, wie zum Beispiel Buttons, Beschriftungen oder Rahmen.

An dieser Stelle wird auf den Stolperstein Layout-Management hingewiesen. Dabei sind frustrierende Erlebnisse bei Einsteigern leider an der Tagesordnung. Würde im Beispiel einfach ein Button hinzugefügt werden, so würde er das gesamte Fenster füllen. Würde die manuelle Größenangabe des Frames weggelassen werden, wäre das Fenster trotz des Buttons 0px groß. Doch gibt es reichlich Möglichkeiten, die Elemente ansehnlich automatisch anordnen zu lassen. Sollten die vorgegebenen Layouts nicht genutzt werden, kann jedes Element pixelgenau positioniert werden. Es muss zunächst das Layout des Fensters auf null gesetzt werden (null ist in diesem Zusammenhang ein Schlüsselwort, kein numerischer Wert). Nun wird als erstes atomares Element ein Button erzeugt und bestimmt, an welcher Position er gezeichnet werden und wie groß er sein soll. Schließlich wird er dem Fenster hinzugefügt. Es werden folgende Zeilen im Konstruktor der View-Klasse ergänzt:

setLayout(null);
JButton Button=new JButton("Test");
Button.setBounds(10, 10, 80, 25);
add(Button);

Wichtig ist, dass wirklich jedes Element absolut positioniert werden muss, sofern das null-Layout verwendet wird. Das gilt aber nicht für die Elemente in hierarchisch untergeordneten Containern, die ihr eigenes Layout benutzen. Container sind die wohl wichtigste Struktur innerhalb von JFrames. Sie sind sozusagen Meta-Elemente, die wiederum eigene Elemente enthalten. Dies soll nun ausprobiert werden. Soll zum Beispiel der Name und das Passwort eines Nutzers abgefragt und ihm die Möglichkeit gegeben werden, die Eingabe abzuschicken oder zu löschen, werden dafür zwei beschriftete Eingabefelder für Text benötigt. Die Textfelder für die Eingabe des Namens und Passworts sollen mit ihrem Label (Beschriftung) nebeneinander stehen und darunter sollen die Buttons angeordnet werden. Die Klasse könnte etwa so aussehen:

public class View extends JFrame {
    View() {
        // Erzeugung der Elemente
        JLabel nameLB= new JLabel("Name:");
        JLabel passLB= new JLabel("Pass:");
        JTextField nameTf= new JTextField(5);
        JPasswordField passPF= new JPasswordField(5);
        JButton resBut= new JButton("Reset");
        JButton sendBut= new JButton("Send");
        
        // Erzeugen der Panels
        JPanel tfPanel= new JPanel();
        JPanel butPanel= new JPanel();
        
        // Hinzufuegen der Elemente zum oberen Panel
        tfPanel.add(nameLB);
        tfPanel.add(nameTf);
        tfPanel.add(passLB);
        tfPanel.add(passPF);
        
        // Hinzufuegen der Elemente zum unteren Panel
        butPanel.add(resBut);
        butPanel.add(sendBut);

        // Einstellungen des Fensters
        setSize(300, 300);
        setTitle("Minimal JFrame");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
        
        // Hinzufuegen der Panels zum Fenster 
        add(tfPanel);
        add(butPanel);
        pack();
        setVisible(true);
    }
}

Listing: View.class

Das Beispiel unter GTK

Das JPasswordfield erlaubt die Eingabe von Text mit anonymisiertem Feedback. Unter Windows würden Sternchen angezeigt werden, unter GNOME Kreise, doch prinzipiell kann je nach Geschmack jedes Feedbacksymbol festlegt werden. Der Parameter 5 bei der Erzeugung der Textfelder gibt die Breite der Felder in Zeichen an. Als Container wird im Beispiel JPanel gewählt, welcher eigene Komponenten aufnimmt. Es wurde kein Layout für die Panels vorgegeben, da das Standardlayout gut passt. Es wird standardmäßig ein FlowLayout verwendet, welches die Elemente von links nach rechts, mit 5 Pixel vertikalem sowie horizontalem Puffer mittig ausrichtet. Dem Hauptfenster wurde ein – syntaktisch leider kompliziertes – BoxLayout entlang der vertikalen Achse zugewiesen. Das sorgt dafür, dass die beiden Panels untereinander angeordnet werden. Die Anweisung setSize(300, 300) wird nun ignoriert, da auch pack() auftaucht. Das bezweckt, dass das Fenster genauso groß wird, wie es die Elemente und das Layout erfordern. Da Puffer in den FlowLayouts vorhanden sind, führt dies nicht zu unschönen Berührungen von Elementen mit dem Rand des Hauptfensters.

Das Beispiel unter dem Human-Thema

Weitere interessante Layouts sind das GridLayout und das BorderLayout. Ersteres ordnet die Elemente, wie der Name vermuten lässt, in einer gleichmäßigen Gitterstruktur an. Letzteres kennt fünf Positionen für seine Elemente: Norden, Osten, Süden, Westen und Mitte. Das mag auf den ersten Blick wenig sinnvoll erscheinen. Doch verglichen mit dem Aufbau moderner Webseiten mit Header, linker Navigation, Inhalt, rechter Navigation und Fußzeile, lassen sich schnell die Parallelen erkennen.

Ein Element, das gezielt eingesetzt werden sollte, ist der Rahmen. Um einen Rahmen um ein Element oder auch um ein Panel zu zeichnen, wird zum Beispiel geschrieben:

Element.setBorder(BorderFactory.
    createEtchedBorder(EtchedBorder.RAISED));

Es würde ein erhobener dreidimensionaler Rahmen um das Element mit dem Namen Element gezeichnet werden. Dieser könnte auch noch beschriftet werden.

Um ein Element mit einem Tooltip auszustatten (ein kurzer informativer Text), wird z. B. um den Button in der View-Klasse damit zu erweitern, folgende Zeile eingefügt:

sendBut.setToolTipText("Sendet die Daten ab");

Schwebt nun der Mauszeiger für einige Zeit über dem Button, wird der Text eingeblendet. Sind die wesentlichen Konzepte der Layouts verinnerlicht und die Funktionsweise von pack(), setSize() und setLayout() nachvollzogen, können ohne grafischen GUI-Builder ansehnliche Applikationen erstellt werden, wobei diese auch nicht verteufelt werden sollen. Tatsächlich sind bei komplexen Projekten GUI-Builder sehr populär.

Benutzerinteraktion

Als Beispiel dafür, wie nun Buttons zum „Leben“ erweckt werden, wird der Reset-Button so implementiert, dass er beide Eingabefelder wirklich löscht. Das Ereignis des Klicks auf den Button muss abgefangen werden. Dies erledigt ein EventListener. Dieser kann als anonyme Klasse direkt in die Klasse geschrieben werden, in der der größte Zusammenhang zur Funktionalität besteht. Fortgeschrittene verwenden eine eigene „Controller“-Klasse, welche sich ausschließlich um solche Funktionen kümmert. In diesem Fall wird diese neue Klasse in die Klasse View geschrieben.

resBut.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
        nameTf.setText();
        passPF.setText();
     }
 });

Damit innerhalb dieser Klasse auf die Textfelder zugegriffen werden kann, müssen sie zuvor als final deklariert werden. Also ist final in den beiden Zeilen zu ergänzen:

final JTextField nameTf= new JTextField(5);
final JPasswordField passPF= new JPasswordField(5);

Es wird also dem Button einen ActionListener hinzugefügt, der die Methode actionPerformed implementiert. Dort kommt die gewünschte Anweisung, in diesem Falle das Löschen der Eingabefelder, hinzu.

Historisches

Um direkt die wichtigste Frage vorweg zu klären: Der Name „Swing“ war der Arbeitstitel dieser Klassenbibliothek (eine logisch zusammengehörige Gruppe von Klassen), weil einer der Entwickler glaubte, dass diese Musikrichtung wieder modern werden würde.

Blickt man auf die Entstehungsgeschichte der „Java Foundation Classes“ (JFC [6]), zu denen Swing gehört, lässt sich eine deutliche Entwicklung zum Positiven feststellen. Während die ersten Versionen von Java noch mit dem unzureichenden „Abstract Windowing Toolkit“ (AWT [7]) ausgeliefert wurden, wurde aus den Fehlern gelernt und eine nahezu vollständig neue Implementierung vorgenommen. Das AWT brachte nur wenige GUI-Elemente mit (einzelne Teile einer grafischen Anwendung wie Buttons, Scrollbalken oder Schieberegler), war zum Teil unhandlich zu programmieren und nur in einem geringen Maße plattformunabhängig, da der Programmierer auf die grafischen Grundelemente beschränkt war, die auf jedem Betriebssystem vorhanden waren. Somit wurde auch teilweise der Speicher des Betriebssystems beansprucht und die Elemente sahen oftmals doch sehr unterschiedlich auf den verschiedenen Plattformen aus. Durch die Folgen der noch nicht ganz durchdachten Ereignisbehandlung – mit Ereignissen sind zum Beispiel das Klicken auf einen Button oder die Eingabe von Text gemeint – war eine saubere Strukturierung des Quellcodes noch nicht richtig möglich.

An dieser Stelle verfolgt Swing einen radikaleren Ansatz. Die Komponenten werden nun größtenteils von Swing selbst gezeichnet, so dass Aufrufe an das darunter liegende Betriebssystem seltener nötig sind. Damit steht eine Vielzahl neuer, komplexer und bereits definierter Elemente zur Verfügung. Dadurch werden die Applikationen noch unabhängiger von der ausführenden Plattform. Die nun mögliche „MVC“-Architektur (Model-View-Controller [8]) macht es dem Entwickler heute leichter, den Code, der jeweils für die Grafikelemente, die Interaktion des Benutzers mit dem Programm und die eigentliche Programmlogik verantwortlich ist, zu modularisieren. Dies erhöht die Lesbarkeit und Wartbarkeit des Codes ungemein. Elemente, die von Swing selbst gezeichnet werden, heißen auch leichtgewichtige Komponenten und analog dazu heißen Elemente, die z. B. durch Aufruf an den Windows-UI-Manager gezeichnet werden, schwergewichtige Komponenten. Letztere sind auch heute noch nötig: Insbesondere die Fenster der höchsten Ebene und Dialoge arbeiten auf diese Weise. Heute verfügen die JFC über sämtliche gängigen Elemente wie Auswahllisten, Buttons, Labels, Checkboxen, Radiobuttons, sowie über komplexe Elemente wie Dateiauswahldialoge.

Als Hauptproblem muss erwähnt werden, dass die Swing-Methoden weitestgehend nicht threadsicher sind, sodass sich der Entwickler selbst um Parallelitätsprobleme kümmern muss.

Performance – Halbwahrheiten und Trugschlüsse

Es ist wahr: Java ist nicht immer die performanteste Lösung. Die Plattformunabhängigkeit wird durch eine relativ hungrige JVM (Java Virtual Machine, die Schicht zwischen dem Bytecode und dem Betriebssystem) teuer erkauft – das ist allerdings eine grundsätzliche Frage, die bei allen derartigen Laufzeitumgebungen eine Rolle spielt, nicht nur bei Java. Es sind die Schritte zu bedenken, die erforderlich sind, um eine Swing-Applikation darstellen zu können. Der Quellcode wird zunächst in einen binären Zwischencode kompiliert. Dieser ist jetzt bereits plattformunabhängig. Soll das Programm nun ausgeführt werden, muss die JVM das Programm in die jeweils plattformkonforme Maschinensprache übersetzen. Und wer jemals grafische Anwendungen in Assembler geschrieben hat, wird sicherlich die Problematik erkennen. Hinter vermeintlich einfachen Fensterelementen können sich immens aufwendige Speicheroperationen verbergen.

Look and Feel

Eine große Stärke von Swing ist die Unterstützung sowohl nativer, als auch freier optischer Themen. Während die Themen von proprietären Betriebssystemen nur auf der jeweiligen Plattform zur Verfügung stehen, gibt es auch freie Java-Themen, die auf jeder Plattform genau gleich aussehen. Namentlich zum Beispiel das moderne „Metal“-Theme, welches noch unterschiedliche Farbschemata enthält, und das etwas altertümliche „Motif“-Theme. Zu den Farbschemata sei gesagt, dass farblich ohnehin völlige Freiheit bei nahezu allen Swing-Elementen besteht. Auf diesem Wege bieten sich sowohl dem Entwickler als auch dem Nutzer Auswahlmöglichkeiten.

Der Entwickler kann ein bestimmtes „Look and Feel“ (L&F) vorgeben, anderenfalls kann der Nutzer das Erscheinungsbild der Anwendung nachträglich durch Parameter im Aufruf beeinflussen. Besonders interessant für Linux-Anwender ist das GTK-L&F, welches originalgetreu wiedergegeben wird. So lassen sich Swing-Anwendungen unter Linux nahtlos in jedes Desktop-Thema integrieren, mitsamt Fensterdekoration und eventuellen Hotkey-Einstellungen.

Darüber hinaus lassen sich eigene Themes erstellen und sogar eine Kombination aus verschiedenen Themes nutzen. Möchte der Entwickler beispielsweise eine Darstellung, die dem jeweils aktuellen Systemthema entspricht, so wird folgende Anweisung, möglichst als ersten Schritt, der Anwendung hinzugefügt. (Ansonsten erzeugt der erste Konstruktoraufruf einer Swing-Komponente bereits implizit eine Instanz der Klasse ComponentUI und gibt damit ein L&F vor.):

UIManager.setLookAndFeel(
    UIManager.getSystemLookAndFeelClassName());

Die Anweisung kann Fehler verursachen, die behandelt werden müssen. Für einen schnellen Test wird lediglich die Import-Anweisung hinzugefügt, die Maus auf den rot markierten Code bewegt und auf „Surround with try/catch“ geklickt.

Andersherum kann der Benutzer mit folgendem Aufruf beispielsweise das GTK-L&F erzwingen, wenn er das Programm aus der Konsole und nicht aus einer Entwicklungsumgebung startet – falls kein anderes explizit vorgegeben ist (MyApp steht im Beispiel für die aufgerufene Klasse):

$ java -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel MyApp

Es sei angemerkt, dass manche Komponenten – milde gesagt – unerwartet dargestellt werden können, wenn während des Design-Prozesses ein anderes L&F angenommen wurde. So kann zum Beispiel der Text auf Buttons im mitgelieferten Metal-L&F manchmal nicht dargestellt werden, da die Schriftgröße zu groß für den Button wird. In diesem Falle würde auf dem Button nur „..“ , anstatt der korrekten Beschriftung angezeigt werden. Diese Feinheiten sollten stets beachtet werden und die unterschiedlichen L&F-Einstellungen vorher getestet werden. Im Zweifelsfall ist es am sichersten, das Metal-L&F vorzugeben.

Eine weitere interessante Möglichkeit ist das Ändern des L&F zur Laufzeit der Anwendung. Es sollte darauf geachtet werden, dass eventuelle Änderungen der Proportionen nicht zu unschönen freien Flächen führen. Es sollte daher nach Änderung des L&F ausgeführt werden (MyFrame steht für den entsprechenden MyFrame.pack()). Das gilt natürlich nur, wenn sich das mit dem verwendeten Layout verträgt. Es lassen sich optische Effekte bis zur völligen Individualisierung des Aussehens jedes einzelnen Elements erzielen, was zum Beispiel für Spiele sehr oft zur Anwendung kommt.

Design

Jeder hat sich schon einmal über eine verwirrende, unzureichend dokumentierte oder schlicht unzureichend funktionale GUI geärgert. Dies sollte genug Motivation sein, es selbst besser zu machen. GUI-Design erfordert Vorüberlegungen, gute Strukturierung des Codes und eine Testphase. Gerade wegen den zahllosen Möglichkeiten, die Elemente anzuordnen, muss die Übersicht bewahrt werden und eine sinnvolle Einteilung festgelegt werden.

Zunächst muss beantwortet werden, wozu die GUI genau dienen soll. Ist sie ein Monitor, eine Kontrollschnittstelle, eine Desktopanwendung oder erfüllt sie gar mehrere Aufgaben? Soll ein Desktopanwendung, die aus mehreren Elementen besteht, erstellt werden, so bietet sich die Nutzung von internen Frames an. In einem großen Hauptfenster können dann beliebig viele weitere Fenster geöffnet werden, welche aber immer noch vom Hauptfenster abhängen. Mit einer Minimierung des Hauptfensters verschwinden also auch alle zusätzlichen Fenster in der Taskleiste. Beispiele für derartige Anwendungen sind Bildbearbeitungsprogramme, Texteditoren oder Chatprogramme. Wenn eine klare Abgrenzung zwischen verschiedenen Aufgaben einer GUI möglich ist, sollte die GUI auch unterteilt werden. Um den Nutzer nicht mit einem Wust aus Daten und Interaktionsmöglichkeiten zu überfrachten, können auch mehrere Fenster erstellt werden, die jeweils bei Bedarf sichtbar geschaltet, fokussiert oder aktiviert werden können.

Beispiel für die Unicode-Unterstützung

Eine andere Möglichkeit ist die Nutzung von Tabs (Karteikarten), mit denen eine GUI in sinnvolle Bereiche unterteilt werden kann.

Soll die GUI ohnehin nicht sehr viele Komponenten enthalten, ist es sinnvoller, lediglich Rahmen um einzelne Gruppen von Elementen zu implementieren. In jedem Falle sollte eine intuitive Beschriftung gewählt und die Unicode-Unterstützung von Swing nicht zu stark missbraucht werden. Elemente, die mit kryptischen Pfeilen, Regenschirmen, Sternen oder sonstigen Dingbats beschriftet sind, erschließen sich dem Nutzer nicht ohne weiteres. Zur Bedienfreundlichkeit tragen noch Tooltips bei, die nahezu für jede Komponente implementiert werden können.

Schlusswort

Mit den JFC steht unter Java eine mächtige Bibliothek zur Entwicklung von grafischen Anwendungen bereit. In einigen Bereichen zeigen sich jedoch Schwächen in der Syntax. Zum Teil sind die Konstruktionen nicht immer einheitlich und intuitiv schlicht nicht zu erfassen. Auch kann die Performance leiden, wenn nicht die integrierten Themes benutzt werden. An der Verbesserung der Performance wird allerding aktuell hart gearbeitet (Stichwort: Just-In-Time-Compiler [9]), sodass noch einige Verbesserungen in Aussicht sind.

Die erste Anlaufstelle für weitere Informationen ist die Tutorial-Page von Sun [10].

Links

  1. http://de.wikipedia.org/wiki/Swing_(Java)
  2. http://www.freiesmagazin.de/freiesMagazin-2009-10
  3. http://java.sun.com/docs/books/tutorial/ui/features/components.html
  4. http://www.eclipse.org
  5. http://wiki.ubuntuusers.de/Alternativen-System
  6. http://en.wikipedia.org/wiki/Java_Foundation_Classes
  7. http://en.wikipedia.org/wiki/Abstract_Windowing_Toolkit
  8. http://de.wikipedia.org/wiki/Model_View_Controller
  9. http://en.wikipedia.org/wiki/Just-in-time_compilation
  10. http://java.sun.com/docs/books/tutorial/uiswing/components/index.html
Advertisements

Java, Teil 1 – Einführung in eine moderne Sprache

Posted in Programmieren on Dezember 1, 2009 by echofalko

JVM, JFC, Applet, Swing … Viele Begriffe schwirren seit nunmehr 13 Jahren in den Welten der IT herum, die ihren Ursprung in der Sprache Java haben. Dieser Artikel als erster Teil einer kleinen Serie soll die Java-Welt ein wenig beleuchten und den Leser in die Lage versetzen, selbst kleine Programme in Java zu schreiben und Code zu lesen, ohne sich in historischen oder technischen Einzelheiten zu verlieren.

Grundsätzliches

Um ein Java-Programm lauffähig zu machen, sind drei Schritte nötig. Zuerst schreibt der Entwickler den Quellcode als java-Datei. Diese Datei kann nun durch den Compiler in eine class-Datei kompiliert werden. Es entsteht ein Bytecode, der immer noch plattformunabhängig ist. Man kann diesen Bytecode auf jeder Plattform ausführen, auf der die Java-Laufzeitumgebung (JVM – Java Virtual Machine) installiert ist. Der letzte Schritt zur Ausführung ist die Übersetzung des Bytecodes in die Befehle der jeweiligen Plattform durch die Laufzeitumgebung.

Die Wahl des Editors

Es ist eigentlich jeder Editor geeignet, um in Java zu programmieren. Man sollte sich aber den Komfort von Syntaxhervorhebung gönnen, um sich die Arbeit ein wenig zu erleichtern. Für GNOME eignet sich der hauseigene Editor gedit, für KDE beispielsweise Kate. Mit zunehmender Komplexität der Programme möchte man aber auf eine ausgereifte Entwicklungsumgebung zurückgreifen.

Die wichtigsten Umgebungen zur Java-Entwicklung sind ohne Zweifel NetBeans [1] und Eclipse [2]. Beides sind freie Programme, die in den gängigsten Distributionen aus den Paketquellen zu beziehen sind und jeweils ihre eigenen Vorzüge und Schwächen haben. Immer wieder zu beobachtende „Glaubenskriege“ bezüglich der Wahl der Umgebung, die meist ergebnislos ausgefochten werden, sollten von keinem seriösen Entwickler ernst genommen werden. Der offensichtlichste Unterschied ist wohl, dass NetBeans einen grafischen GUI-Builder enthält, mit dem man per Drag & Drop optisch ansprechende GUIs erstellen kann, ohne tiefgehende Kenntnisse über die Swing-Bibliothek [3] zu benötigen.

Andererseits erzeugt NetBeans mit seiner Vorlage für eine grafische Applikation bereits eine erhebliche Menge Code (300 Zeilen), welcher für Einsteiger und vielleicht sogar für Amateure sehr schwer verständlich ist. Es besteht also durchaus die Gefahr, mit dem GUI-Builder in eine Sackgasse zu laufen, wenn man den produzierten Code nicht vollständig versteht. Daher ist ein Einstieg in Swing mit dem GUI-Builder nur eingeschränkt zu empfehlen. Für Eclipse ist ein GUI-Builder bis dato nur in einem kommerziellen Zusatzpaket erhältlich. In der nächsten Ausgabe wird die Grafikprogrammierung unter Java noch ausführlich besprochen, ebenso die Vorbereitung einer Entwicklungsumgebung. In jedem Falle sind beide Umgebungen absolut ausgereift, reich an Features, leicht erweiterbar und nehmen eine absolut gleichberechtigte Stellung im Bereich der professionellen Java-Entwicklung ein.

Installation und Vorbereitungen

Da Sun Java [4] sehr verbreitet ist, werden die meisten Nutzer bereits diese Laufzeitumgebung installiert haben. Um dies zu überprüfen, fragt man die aktuell benutzte Version mitab. Die aktuellste Version von Sun Java ist „1.6.0_16“. Sollte die Versionsabfrage etwas in der Art

$ java -version
java version „1.6.0_10“
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)

java version „1.5.0“
gij (GNU libgcj) version 4.3.2

ausgeben, hat man kein Sun Java, sondern ein anderes Java (hier GNU Compiler for Java [5]) installiert, was aber auch nicht weiter schaden sollte.

Alternativ hilft auch ein Besuch der offiziellen Sun-Testseite [6], die aber natürlich nur ein Ergebnis liefert, wenn Java-Unterstützung im Browser eingerichtet ist.

Nun braucht man noch die notwendigen Bibliotheken, um Programme selbst kompilieren zu können. Zunächst muss man sich nun entscheiden, welche Version von Java man installieren möchte. Das Unternehmen Sun ist Urheber von Java und stellt mittlerweile Versionen für Linux bereit, die zumindest unter der i386- und amd64-Architektur laufen. Man benötigt das JDK (Java Development Kit), welches man nicht mit der JRE (Java Runtime Environment) verwechseln darf, welche nur das Ausführen von Java-Programmen ermöglicht. Das offizielle Java von Sun soll zukünftig unter der GPL veröffentlicht werden, sodass man diesbezüglich wohl keine Bedenken haben sollte. Man installiert das offizielle Java beispielsweise durch das Paket sun-java6-jdk. Die bereits jetzt komplett freie Version OpenJDK lässt sich in den gängigsten Distributionen durch das Paket openjdk-6-jdk installieren. Sollten dennoch außerordentliche Probleme auftreten, hilft Ubuntu-Nutzern die Wikiseite [7] in den meisten Fällen weiter.

Das erste Programm

Das beliebte „Hello World“ ist in Java auf den ersten Blick komplex. Es wird jedoch jeder einzelne Begriff genau erklärt, um niemandem mit Halbwissen und Vermutungen zurückzulassen.

class MyClass {
public static void main(String[] args)
{
System.out.println(„Hello World“);
}
// Dies ist ein einzeiliger Kommentar.

/* Dies ist ein Blockkommentar,
der ueber mehrere Zeilen geht.
*/
}

Listing: MyClass.java

Der Quelltext wird als Datei MyClass.java gespeichert. Danach bewegt man sich in der Konsole in das entsprechende Verzeichnis und kompiliert das Programm mit

$ javac MyClass.java

Anschließend startet man das Programm mit

$ java MyClass

Hinweis: Die Endung .class wird nicht mit angegeben.

Erklärung des Beispiels

Die erste Zeile leitet die Klasse ein, den äußeren Rahmen einer Java-Anwendung. Man beachte, dass der Bezeichner der Klasse (hier MyClass) groß geschrieben wird.

Die zweite Zeile ist die Kopfzeile der Hauptmethode der Klasse, die immer main heißen muss. Eine Methode ist ein Unterprogramm. Hat sie einen Rückgabewert, spricht man von Funktionen, ansonsten auch von Prozeduren. Sie ist der Einstiegspunkt, an dem ein Programm mit der Ausführung beginnt. Die Kopfzeile der Hauptmethode muss in jedem Programm genau so aussehen. public besagt, dass die Methode von außerhalb der Klasse aufgerufen werden kann, static besagt, dass die Methode direkt aus der Klasse aufgerufen wird (ohne Objekt), void legt schließlich fest, dass die Methode keinen Rückgabewert hat. In den runden Klammern steht der Parameter, der dieser Methode übergeben wird. In diesem Falle ein Array (eine Art von Liste) von Strings (Zeichenketten), auf die in der Methode unter dem Namen args (Argument) zugegriffen werden kann.

Nun beginnt eingeschlossen von den geschweiften Klammern der eigentliche Programmcode. Es wird die Methode println aufgerufen, die unter dem Pfad System.out erreichbar ist. Die Methode gibt eine Zeichenkette mit Zeilenumbruch auf der Konsole aus. Diese Zeichenkette wird in runden Klammern übergeben. Am Ende jeder Anweisung muss ein Semikolon stehen (auch wenn es die letzte ist).

Schließlich wird die Klasse noch durch eine geschweifte Klammer geschlossen. Das sind zunächst eine Menge Schlüsselwörter für eine so simple Funktionalität. Doch ist gerade diese strikte Strukturierung unter Java in vielen Situationen vorteilhaft.

Was zeichnet Java aus?

Wie am Beispiel erkennbar, ist Java sehr streng typisiert. Dies ist nicht zu vergleichen mit Sprachen, die auch als Skripte ausgeführt werden können wie zum Beispiel Python. Der Code wird dadurch umfangreicher. Allerdings erkennt der Compiler Fehler im Code sehr präzise und zwingt dem Entwickler einen sauberen und typsicheren Stil auf. Typsicherheit wird bei Java sehr groß geschrieben. Das bedeutet, dass zu jeder Zeit während der Laufzeit des Programms gewährleistet ist, dass eine Variable stets den richtigen Typ hat und so verwendet werden kann, wie es die Programmlogik erfordert. Es kann also nicht passieren, dass ein Programm anstandslos kompiliert, obwohl eine Zeichenkette (String) durch eine ganze Zahl (Integer) dividiert wird (was eine nicht definierte Operation wäre).

Syntaktisches

Die wichtigsten Syntaxregeln sind bereits im Beispiel erkennbar. Klassen, Methoden und Blöcke (logisch zusammenhängende Anweisungen) werden von geschweiften Klammern umschlossen. Jede Anweisung wird mit einem Semikolon beendet. Methoden und Variablen werden mit Angabe ihres Pfades aufgerufen. Unterverzeichnisse werden mit Punkten getrennt.

Fügt man eine weitere Klasse hinzu und legt sie im gleichen Verzeichnis ab wie die andere Klasse, sind sich die Klassen untereinander bekannt.

class MyClass2
{
static String text=“Hallo Welt“;
}

Listing: MyClass2.java

Diese Klasse enthält nur eine Variable, nämlich eine Zeichenkette (String), die text heißt und den Inhalt  Hallo Welt hat. Sie ist als static deklariert, damit sie eine Eigenschaft der Klasse ist, nicht von einem Objekt (dazu später mehr). Diese Klasse lässt sich kompilieren, jedoch nicht ausführen. Es fehlt die main-Methode. Doch die Klasse aus dem ersten Beispiel kann nun auf die Variable der zweiten Klasse zugreifen. Man ergänze die Hauptmethode der Klasse MyClass durch die Anweisung

System.out.println(MyClass2.text);

Sind beide Klassen (neu) kompiliert, wird auf der Konsole nun auch  Hallo Welt ausgegeben:

$ javac MyClass.java
$ javac MyClass2.java
$ java MyClass
Hallo Welt

Primitive Datentypen und Mathematik

In Java kann man sehr ähnlich wie in jeder anderen Programmiersprache mathematische Operationen durchführen. Die gängigsten Datentypen und Operationen sollen im folgendem Beispiel gezeigt werden.

class Beispiel {

public static void main(String[] args) {

 

// Die Variable zahl1 wird deklariert.

int zahl1;

 

// zahl1 wird initialisiert es wurde

// ihr ein Wert zugewiesen.

zahl1 = 7;

 

// zahl2 wird in einer Anweisung

// deklariert und initialisiert.

int zahl2 = 3;

System.out.println(zahl1 + zahl2);

// Ausgabe: 10

System.out.println(zahl1 * zahl2);

// Ausgabe: 21

System.out.println(zahl1 / zahl2);

// Ausgabe: 2
// „double“ ist genauer

double zahl3 = 7.0;
System.out.println(zahl3 / zahl2);

// Ausgabe: 2.33333…

}

}


Listing: Beispiel.java

Warum wird bei der ersten Division als Ergebnis der Wert 2 ausgegeben? In dem Beispiel wird mit ganzen Zahlen (int) gerechnet. Die Nachkommastellen werden einfach abgeschnitten. Wird ein genaues Ergebnis gewünscht, muss ein anderer Datentyp benutzt werden, wie zum Beispiel double.

Klassen und Objekten

Objekte können in Java für nahezu alle greifbaren Elemente des Programms stehen. Diese können simpel (eine Zahl) oder komplex (eine Liste von Hashmaps, in denen offene Datenbankverbindungen auf die jeweiligen Nutzer abgebildet werden) sein. Eine Tatsache muss allerdings beachtet werden: Primitive Datentypen sind in Java keine Objekte. Dies sind beispielsweise int oder double (später dazu mehr). Jedes Objekt hat einen bestimmten Typ. Im Beispiel MyClass2 ist die Variable text ein Objekt vom Typ String. Somit ist sichergestellt, dass ein Objekt nur so benutzt werden kann, wie es für seinen Typ definiert ist. Ist für Objekte des Typs „Turnschuh“ beispielsweise die Methode „volltanken“ nicht definiert, obwohl sie im Code aufgerufen wird, würde der Compiler dies sofort erkennen.

Eine Klasse ist in Java nichts anderes als ein Bauplan für Objekte eines bestimmten Typs. Der Bezeichner der Klasse ist gleichzeitig der Bezeichner des Typs der Objekte, die Instanzen dieser Klasse sind.

class Person {
public String vorname;
public String nachname;

public void printName()
{
System.out.println(vorname+“ „+nachname);
}
}

Listing: Person.java

Es wurde ein neuer Datentyp namens Person erzeugt. Man beachte, dass die beiden Variablen vorname und nachname nun nicht als static deklariert werden. Das hat zur Folge, dass jedes Objekt vom Typ Person nun die beiden Variablen „hat“. Jede Person hat ihre eigenen Variablen. Somit sind die Variablen keine Eigenschaften der Klasse mehr, sondern von den Instanzen, die sie erzeugt. Die Methode printName ist ebenfalls nicht statisch, sie wird also nur von Objekten aufgerufen. Die runden Klammern nach dem Bezeichner sagen aus, dass die Methode keinen weiteren Parameter erwartet. Sie gibt den Vornamen, gefolgt von einem Leerzeichen (Zeichenketten werden mit + verbunden), und dann den Nachnamen auf der Konsole aus.

Das nächste Beispiel Person2.java erzeugt nun eine Person, weist den Variablen Werte zu und ruft die Methode printName auf.

class Person {
public String vorname;
public String nachname;

public void printName()
{
System.out.println(vorname+“ „+nachname);
}

public static void main(String[]args)
{
Person einePerson = new Person();
einePerson.vorname = „Hans“;
einePerson.nachname = „Maier“;
einePerson.printName();
}
}

Listing: Person2.java

Was geschieht in diesem Programm? Der Einstiegspunkt ist wieder die main-Methode. Es wird eine Variable vom Typ Person mit dem Bezeichner einePerson deklariert. Dieser Variable wird ein neu erzeugtes Objekt zugewiesen, das durch new erzeugt wird. Dadurch wird der sogenannte Konstruktor aufgerufen, der eine Methode ist, die ein neues Objekt zurückgibt. Hier steht kein Parameter in den runden Klammern, da der immer implizit vorhandene parameterlose Konstruktor aufgerufen wird. Nun kennt die Laufzeitumgebung eine Person mit dem Bezeichner einePerson, die jedoch noch keine zugewiesenen Werte für vorname und nachname hat. Dies ändert sich in den nächsten beiden Anweisungen. Über die Punktnotation werden die Variablen aufgerufen, und ihnen ein Wert zugewiesen. Letztendlich werden diese Variablen durch Aufruf von printName mit der Person einePerson auf der Konsole ausgegeben.

Weiterführendes zu Klassen

Das Klassenkonzept kann sehr intuitive Programmierung ermöglichen. Es ist beispielsweise möglich, mit dem Schlüsselwort extends eine Klasse aus einer anderen Klasse abzuleiten. Man spricht von Vererbung. Man könnte etwa eine Klasse Mitarbeiter erstellen, welche die Variable personalnummer (deklariert als int, also als ganze Zahl) enthält, und diese Klasse von Person ableiten. Jeder Mitarbeiter hätte damit automatisch auch die Variablen vorname und nachname, sowie die Methode printName, ohne dass man dies noch einmal in den Code schreiben muss. Die Syntax wäre:

class Mitarbeiter extends Person {
public int personalnummer;
}

Listing: Mitarbeiter.java

Nun „ist“ jeder Mitarbeiter auch eine Person. Und alle Methoden die für eine Person definiert sind, können auch von einem Mitarbeiter aufgerufen werden. Umgekehrt ist das natürlich nicht der Fall. Eine Person, die kein Mitarbeiter ist, hat die Variable personalnummer nicht. Der Compiler würde dies bemerken.

Es kann jedoch auch zu sehr abstrakten Beziehungen zwischen den Klassen kommen, die nicht unbedingt dem intuiven Verständnis entsprechen. Es ist beispielsweise möglich, dass ein Objekt eine Variable hat, die eine Liste ist, in dem das Objekt selbst noch einmal enthalten ist. Der Fantasie sind dort keine Grenzen gesetzt. Man denke nur an ein Kind, dass seinen Vater als Variable hat, während der Vater auch seine Kinder als Variablen hat.

Ausblick

Im nächsten Teil der Serie wird die Grafikprogrammierung mit Java ausführlich beschrieben.

Links

  1. http://www.netbeans.org/
  2. http://www.eclipse.org/
  3. http://de.wikipedia.org/wiki/Swing_(Java)
  4. http://www.java.com/de/
  5. http://gcc.gnu.org/java/
  6. http://www.java.com/de/download/help/testvm.xml
  7. http://wiki.ubuntuusers.de/Java

Rezension: Coding for Fun

Posted in IT on Mai 12, 2009 by echofalko

Verlag: Galileo Computing, 2008
Diesen Artikel schrieb ich für freiesmagazin.
Womeringer möchte, dass der Leser allen Ernstes Spaß mit dem Computer hat. Dies ist kein Widerspruch. Mit dem nötigen mathematischen und technischen Hintergrundwissen ausgerüstet, tritt der Leser eine Reise durch die Geschichte der Programmierung an und stößt dabei auf ungewöhnliche, nostalgische, lehrreiche oder auch einfach nur unterhaltsame Programme, die stets zum Nachmachen und Mitmachen einladen.

cover

Allgemeines

Zum Lieferumfang des über 500 Seiten starken Softcover-Buches gehört eine umfangreiche Begleit-DVD, die alles nötige beinhaltet, um die vorgestellten Programme selbst auszuprobieren und weiterzuentwickeln. Auf der DVD befinden sich u.A. Quelltexte, vorkompilierte Programmbeispiele, hilfreiche Tools für die Erstellung von Diskettenabbildern, FreeDOS und die Desktop-CD von Ubuntu. Letztere entspricht in der ersten Auflage leider noch der Version 7.10, sodass man mittlerweile lieber eine aktuellere Version installieren sollte. Es sei noch angemerkt, dass einige mitgelieferte Programme als .exe vorliegen, und damit eine fehlerfrei Ausführung mit Wine nicht immer garantiert ist.
Neben den vielen anschaulichen Beispielen zu nahezu jedem Programmierparadigma, vermittelt der Autor zunächst unabdingbares theoretisches Wissen. Hier wird auch die eigentliche Zielgruppe bereits deutlich: Ohne Interesse an Mathematik und Technik wird man an diesem Buch wohl keine Freude haben, obwohl der Titel und die jungen Menschen auf dem Cover vielleicht den Eindruck eines jugendfreundlichen Buches vermitteln. So wird der Leser bereits im ersten Abschnitt mit vermeintlichen Schreckgespenstern aus der theoretischen Informatik wie der Turing-Maschine, der Turing-Vollständigkeit oder dem Gödelschen Unvollständigkeitssatz konfrontiert. Die Erläuterungen sind gemessen an der Kürze der Ausführungen aber schlüssig, logisch und auch für Hobbyisten nachvollziehbar, wobei im gesamten Buch auf mathematischen Formalismus wohlwollend verzichtet wird. Der Gebrauch von einschlägigen Tools zur Virtualisierung wird dringend empfohlen und ist im Anhang des Buches freundlicherweise genau beschrieben, sodass hier keine Vorkenntnisse nötig sind. Die Gratwanderung zwischen Einsteigerfreundlichkeit und Anspruch versucht der Autor durch Kenntlichmachung von einzelnen Abschnitten zu meistern. Es werden Abschnitte für Kenner mit einem Pacman und Abschnitte für Könner, etwas humoristisch, mit einem Geist gekennzeichnet. So kann man getrost mal einen Abschnitt überspringen, dem man sich nicht gewappnet fühlt, um an späterer Stelle noch einmal zurückzukommen. Zwischendurch dienen immer wieder Abschnitte über die geschichtliche Entwicklung der Auflockerung.

BASIC und Assembler

Die Zeitreise beginnt mit der Sprache BASIC. Hierzu bedient man sich zunächst eines virtuellen DOS, welches man zuvor z.B. mit VirtualBox angelegt hat. Hier erlent man spielerisch das GOTO-Prinzip und bekommt einen großen Happen Nostalgie und ein Erfolgserlebnis als Belohnung. Als nächstes kann man mit dem Emulator x64 die alten Zeiten richtig wieder aufleben lassen und mit dem legendären Commodore 64 samt eingebautem BASIC-Interpreter Retroluft schnuppern. Eine Laufschrift und eine grafische Spielerei mit geometrischen Figuren werden hier vorgestellt, anhand derer man den Umgang mit zählenden Schleifen lernt.

Wer sich schon immer einmal mit seiner CPU unterhalten wollte, erhält eine kleine Einführung in die Assembler-Programmierung. Auch hier nutzen wir wieder eine virtuelle DOS-Machine und einen mitgelieferten hübschen grafischen Debugger, der es uns ermöglicht, Schritt für Schritt einzelne Befehle auszuführen. Dabei hält uns die mehrfach geteilte Ansicht stets auf dem Laufendem was den Stack, die nächsten Befehle und die Register angeht.

Wer den letzten Satz nicht vollständig verstanden hat, ist genau auf dem richtigen Wissensstand für dieses Kapitel. Die wichtigsten Befehle und Register werden erklärt, wobei die Erläuterung des Stacks, dessen Verständnis unabdingbar ist, leider kaum angerissen wird. Hier sind also Vorkenntnisse, oder die Bereitschaft sich über das Buch hinaus mit diesem Thema zu beschäftigen nötig.

Spiele und bunte Landschaften

Selbstverständlich kommen die von so vielen Menschen geliebten Computerspiele nicht zu kurz. Hier ist der erste Halt der Klassiker Pong. Während die Urfassung noch in Hardware realsiert war, wird uns hier der komplette Quellcode als Java-Projekt für die Entwicklungsumgebung Eclipse zur Verfügung gestellt. Etwas verruchter wird es beim Spiel „Hack The Game V. 1.21“. Hier kann man seine kriminelle Energie entladen und Daten von fremden Hosts stehlen, löschen und weitere Schandtaten begehen. Auf alle Fälle ein sehr unterhaltsames Spiel, das trotz der eindeutigen Ziele des Protagonisten pädagogisch wertvoll ist, da man beinahe zwangsläufig langjährige virtuelle Haftstrafen antreten muss. Für Grafikinteressierte ist auch eine Anleitung für das Tool Blender, sowie ein Programmbeispiel in Java3D gegeben.

Das Apfelmännchen und das Chaos

Besondere Erwähnung gebührt dem Abschnitt über Fraktale. Neben der durchaus lesenswerten Erklärung dieser Muster mit Selbstähnlichkeiten und Skaleninvarianzen, wird auf das Programm <> verwiesen, welches man als Mathematik- und/oder Kunstfreund nicht auslassen sollte. Alternativ kann man auch die neuste Version direkt von der Projektseite kostenfrei herunterladen. Es bietet sehr aufschlussreiche Präsentationen zu diesem Thema und eine verblüffende Zoom-Funktion für die angezeigten Fraktale. Dies schafft einen nahtlosen Übergang zu rekursiven Programmen, die beispielhaft anhand eines kleinen Java-Programms vorgestellt werden, welches ein einfaches Fraktal mit erstaunlich wenig Code erzeugt. Könner werden auch eingeladen, ihre eigenen Visualisierungen mit Java zu realisieren. Was zunächst wie eine Spielerei wirkt, ist in der Realität Grundlage dafür, naturgegebene Strukturen in Programmen nachzubilden und aus der heutigen Informatik nicht mehr wegzudenken.

Betriebssysteme – Vergessene Legenden

Beim Thema Betriebssysteme wird etwas weiter ausgeholt. Mit einem flüssig zu lesenden Abriss über die Geschichte erhält man Einblicke in längst vergessene Kapitel, insbesondere der GUI-Historie. Oberflächen wie Smalltalk 80, GEM (zum ausprobieren auf der DVD mitgeliefert) oder das Echtzeitsystem QNX werden vorgestellt. Über den C64 bis zu modernen Linux-Distributionen (als Beispiel wird Ubuntu vorgestellt) erhält man einen Überblick über die Entwicklung von Betriebssystemen und der Programmiersprachen, die mit den Systemen einhergingen. Besonders anschaulich ist ein in Java implementierter Netzgraph, der die Verwandtschaftsbeziehungen zwischen den Prorgammiersprachen verdeutlicht.

KI – Ist Skynet möglich?

Der Traum vom denkenden Rechner ist noch älter als die Informatik. Dieses Kapitel bringt dem Leser die unterschiedlichen Ansätze näher, mit denen man versucht, schwache oder gar starke künstliche Intelligenzen zu erzeugen. Die Simulation von neuronalen Netzen wird unter anderem anhand des Tools MemBrain erklärt. Hiermit kann man beispielsweise einem Sytem aus nur sechs Neuronen Wissen antrainieren, welches auf Abfrage auch korrekt wiedergegeben wird. Mit einer solchen assoziativen Speicherung erhält man sogar Antworten auf Fragen, die dem System nie explizit beigebracht wurden. Die Antwort lässt sich nicht vorhersehen. Hier liegt die Analogie zum menschlichen Verstand: Wissen wir etwas nicht, so versuchen wir Schlüsse zu ziehen. Hier ist also sehr viel Spielraum für weiterführende Experimente mit diesem Tool. Eine andere Herangehensweise bieten die vorgestellten Programmiersprachen Smalltalk, Lisp und Prolog. Letztere gibt beispielsweise die Möglichkeit, eine Wissensbasis mit allgemein gehaltenen Aussagen zu schreiben, anhand derer dann konkrete Fragen an das Programm gestellt werden können. Hier ergeben sich allerdings keine unvorhersehbaren Antworten, da z.B. durch Rekursion oder Backtracking so lange Aussagen abgeleitet werden, bis eine verlässliche Antwort gefunden ist, oder bis die Unmöglichkeit einer verlässlichen Antwort bewiesen ist. Anschaulich dargestellt: Wenn ich nur weiß, dass die Straße immer glatt ist, wenn sie kälter als 0°C ist, kann ich stets bejahen, dass die Straße glatt ist wenn es friert. Andererseits kann ich nicht mit Sicherheit sagen ob es friert, nur weil die Straße glatt ist.

Programmieren lernen

Der letzte Abschnitt ist eine Einführung in die Programmierung in der Sprache BASIC mit Hilfe der unfreien Entwicklungsumgebung VB Express von Microsoft. Anhand eines Ameisenvolkes kann man spielerisch mit der Umgebung und der Sprache vertraut werden. Praktischerweise liegt das umfassende Buch „Visual Basic 2005“ als html Version bei, sodass man sich tiefgründig mit der Sprache auseinandersetzen kann.

Fazit

Womeringer überzeugt mit guter Auswahl seiner Beispiele und mit einem sehr flüssigen Schreibstil. Man lässt sich gern mit auf die Reise nehmen und möchte alles ausprobieren und verstehen. Dies wird aber leider nicht jedem gelingen. Die Materie ist durchaus anspruchsvoll und nicht immer einsteigerfreundlich. Für den ambitionierten Einsteiger, der bereits wenigstens eine moderne Programmiersprache in Grundzügen verstanden hat, beiten sich Herausforderungen, die ihn stets fordern. Experten der Programmierung finden zumindest spannende Beispiele in ungewohnten Gefilden, die ihnen vielleicht bis dato verborgen blieben. Anfänger können angesichts der Fülle an thematisch völlig unterschiedlichen Kapiteln leicht den Überblick verlieren. Auch die Tatsache, dass die Kapitel nie erschöpfende Ausführungen enthalten, tragen hierzu bei. Man darf aber nicht vergessen, dass das Buch nicht den Anspruch hat ein Lehrbuch zu sein. Dazu treffend im Vorwort:

Es wäre schön, wenn sich Leser finden würden, die das Buch als Sammlung von Anregungen verstehen.

Erfahrenen Linux-Benutzern könnte noch negativ auffallen, dass von den 573 Seiten stolze 182 auf den Anhang fallen, der Anleitungen zur Installation von VirtualBox, Xen, FreeDOS, Ubuntu, Java und weiterer Software enthalten. Für weitere Informationen und Leseproben bietet sich ein Besuch der Seite des Verlages an.