Kapitel 1 Der objektorientierte Ansatz Programme unterstützen uns im täglichen Leben in fast allen Bereichen. Ob es die programmgesteuerte Waschmaschine oder das Handy mit Internet-Zugang, die Kasse im Supermarkt oder die Verwaltung von Adresslisten auf einem elektronischen Assistenten, das Erstellen und Anzeigen von Bildern und ganzen Filmen oder der Autopilot im Flugzeug ist, Programme werden eingesetzt, um Probleme zu lösen oder Aufgaben zu erfüllen. Ein Programm steuert, regelt und verwaltet. Dazu verwendet es Modelle realer Objekte, stellt sie dar, überträgt sie, vermittelt zwischen unterschiedlichen Anwendungen. Ein Versuch diese unterschiedlichen Aspekte in einem Satz zusammenzufassen, führt zu folgender Aussage: Die Ausführung eines Programms ist die Simulation eines Modells der realen oder einer imaginären Welt. Programmieren bedeutet demzufolge die Modellierung einer Situation und die Umsetzung des Modells in ein ausführbares Programm. Der Weg von einem Problem zu einem lauffähigen Programm gliedert sich in mehrere Phasen, die durchaus verschiedener Natur sein können und an deren letzter Stelle erst die eigentliche Programmierung steht. Wir unterscheiden drei Hauptphasen: 1. Analyse des Problems, 2. Programmentwurf und 3. Implementierung in einer Programmiersprache Wir betonen in diesem Tutorial natürlich den letzten Punkt, werden aber stets darauf bedacht sein, auch Modellierungsfragen zu besprechen, weil in zutreffender Analyse und geschicktem Entwurf der Schlüssel zum erfolgreichen Programm liegt. Die Terminologie, in der man das Problem analysiert, die also aus dem Anwendungsbereich stammt und noch mehr die, in der man das Programm entwirft, spiegelt sich im objektorientierten Fall oft direkt in der Programmiersprache wider. 2 Kapitel 1: Der objektorientierte Ansatz Man kommt relativ schnell zu ausführbaren Prototypen, die dann erst nach und nach zum endgültigen Programm verfeinert werden. Je mehr Begriffe aus der Welt des Anwenders, der das Problem gestellt hat und das Programm später benutzen will, verwendet werden, umso leichter wird der Dialog zwischen Programmierer und Anwender. Das entbindet natürlich nicht von der notwendigen mathematischen oder strukturellen Aufbereitung des Modells. Objektorientierter Entwurf und Programmierung verwenden Konzepte wie das Vergeben von Aufträgen, das Verbergen von überflüssiger Detailinformation und die Interaktion eigenständiger "Wesen". Die Ausdrucks- und Denkweise aus dem Bereich der Anwendung lassen sich besser als bei der traditionellen Programmierung in das Programm übertragen. 1.1 Ein einführendes Beispiel Beispiel 1: Unterhaltungselektronik Unsere Freizeitbeschäftigung wird heute mehr und mehr von unterschiedlichen elektronischen Geräten bestimmt. Computerspiele, Audio-CDs, Musikkassetten (MCs) usw. sind in fast jedem Haushalt zu finden. Etwas Ordnung in diese Vielfalt zu bringen soll unser Ziel sein. Beschränken wir uns auf einen kleinen Ausschnitt: Ein Walkman spielt eine Kassette ab. Dass er dazu immer gehen muss, ist sein Problem. Bequemer hat es der Discman, der natürlich Audio-CDs erklingen lässt. Noch nicht ganz erwachsen ist hingegen der Gameboy für Computerspiele. Objekte sind aktiv Wir unterscheiden also zwischen aktiven Objekten (Männern und Jungen), die etwas tun, und passiven Objekten (CDs, MCs und Spiele), die unterschiedliche Inhalte darstellen. Diese Unterscheidung ist ganz hilfreich, aber letztlich können auch die passiven Medien künstlich aktiviert werden, indem sie etwa mitzählen, wie oft sie schon aufgelegt wurden oder zumindest Auskunft darüber geben, welches Gerät sie benötigen. So kommen wir der weit verbreiteten Sicht eines objektorientierten Programms als eine Menge kommunizierender Objekte schon nahe. Ein Discman erhält eine CD und spielt diese ab. Er reagiert darauf durch seine ihm angemessene Verhaltensweise. Die Objekte können also agieren, sie kennen gewisse Methoden, die ihr Verhalten bestimmen. Diese Methoden sind allen gleichartigen Objekten zu eigen, alle Audio-CDs können von einem Discman gespielt werden, jedoch nicht von einem Walkman. 1.1 Ein einführendes Beispiel 3 Objekte gehören zu Klassen Jedes Objekt wird als ein Exemplar einer Klasse aufgefasst, jede CD ist ein individuelles Exemplar der Klasse aller CDs. Neben den Methoden verfügen die Objekte einer Klasse auch über gemeinsame Attribute, die ihren Zustand beschreiben, z.B. kann eine CD noch original verpackt, noch nie gespielt oder schon oft gehört sein. Dieser Zustand eines Objektes beeinflusst die Verhaltensweise, indem abhängig von seinem Wert gewisse Methoden aufgerufen werden können, oder andere unterschiedlich reagieren. Eine Klasse legt also nicht nur Methoden fest, sondern auch Eigenschaften oder Attribute, deren Werte für jedes individuelle Objekt verschieden sein können. Objekte haben eine Identität, auch solche mit identischen Attributwerten können unterschieden werden. Objekte werden im Verlauf eines Programms geschaffen, konstruiert. Bei der Konstruktion werden einige Attribute gesetzt, andere kommen während des Programmlaufs hinzu. Normalerweise kann der Wert eines Attributes verändert werden. Beziehungen Objekte stehen in Beziehungen zueinander. Wenn wir für eine Klasse ein rechteckiges Bild wählen, in dem der Klassenname, die Attribute und die Methoden aufgeführt sind, so lässt sich folgendes Diagramm (UML Klassendiagramm) zeichnen. Abbildung 1: Beziehungen zwischen Klassen Auch Objekte werden durch ein Rechteck dargestellt, auf welches ein mit dem Objektnamen bezeichneter Pfeil verweist. Das Szenario, dass eine Karajan CD, ein Exemplar der Klasse CD, dessen Attribut interpret den Wert "Karajan" besitzt, auf einem Discman der Marke Headache und eine Kassette von Queen gleichzeitig auf einem Walkman der Marke Marathon laufen, wird durch folgendes Bild veranschaulicht. 4 Kapitel 1: Der objektorientierte Ansatz Abbildung 2: Beziehungen zwischen Objekten 1.1.1 Aktive Objekte Ganz wichtig im objektorientierten Programmieren ist die Idee, dass alle Aktivität von Objekten ausgeht. Im angeführten Beispiel mit der Unterhaltungselektronik lässt sich das noch relativ gut nachvollziehen. Beispiel 2: aktive Objekte Im obigen Bild spielt ein Discman mit dem Namen discy die CD mit dem Namen cd1. Das lässt sich unmittelbar als Java Fragment schreiben. discy.spiele(cd1); 1.1.2 Klassifikation Die Klassifikation der Objekte in verschiedene Klassen, kann noch weiter getrieben werden. So lassen sich CDs und MCs zum Oberbegriff Musikmedium zusammen fassen. Auch die Tatsache, dass beide gleich lautende Attribute besitzen, regt zu dieser Verallgemeinerung an. 1.1 Ein einführendes Beispiel 5 Abbildung 3: Klassifikation von Musikmedium Dieses Bild sollte wie folgt gelesen werden: Jede CD und jede MC ist ein Musikmedium und hat deshalb ein Attribut, welches den Interpret bezeichnet. Eine MC kann gelöscht werden, eine CD nicht. Diese Ist-ein Beziehung bezeichnet man im objektorientierten Programmieren als Vererbung1 Eine MC hat und kann alles, was ein Musikmedium kann und bietet darüber hinaus noch die Methode istLeer() an. Ebenso gehören alle Abspielgeräte zu einer Klasse, Kategorie oder Hierarchie. Jedes Gerät besitzt ein Attribut, welches den Firmennamen repräsentiert und eine Abspielmethode. Die wird allerdings erst dann festgelegt, falls klar ist, um was für ein Gerät es sich handelt. Es ist also nicht sinnvoll Objekte der Klasse Gerät anzulegen, denn wir wissen nicht wie das Abspielen funktioniert. Die Klasse Gerät ist abstrakt2. Trotzdem ist es möglich und sinnvoll etwa eine Liste verschiedener Geräte zu verwalten, von denen jedes eine spezifische Abspielmethode besitzt. Jedes Gerät verhält sich also seinem Typ gemäß3. Abbildung 4: Klassifikation von Geräten 1 Siehe auch: Vererbung (S. 173) Siehe auch: Abstrakte Klassen (S. 194) 3 Siehe auch: Polymorphie (S. 189) 2 6 Kapitel 1: Der objektorientierte Ansatz 1.1.3 Datenkapselung Ein weiteres Merkmal der objektorientierten Vorgehensweise ist die konsequente Umsetzung der Datenkapselung. Darunter versteht das Verbergen von unnötigen Detailinformationen. So ist es für den Aufruf einer Methode nicht wichtig, die Implementierung genau zu kennen. Die Wartbarkeit und Lesbarkeit eines Programms wird erhöht, wenn für das Ändern von Attributen Zugriffsrechte vergeben werden. Am einfachsten ist die Regel, dass im Sinne der Eigenverantwortung der Objekte, Attributwerte nur von dem Objekt selbst verändert werden sollten. Die Attribute interpret und marke sollten in unserem Beispiel nur bei der Konstruktion gesetzt werden. Wenn ein Computerspiel hingegen mitzählen soll, wie oft es bereits aufgerufen wurde, so ist ein schreibender Zugriff auf das Attribut anzahl eigentlich nur im Zusammenhang mit dem Abspielen erwünscht. Das Attribut wird gekapselt. 1.2 OOP im Überblick Wir stellen die wesentlichen Aspekte des objektorientierten Ansatzes zusammen: • Objekte sind eigenständige Einheiten die einen Zustand haben. • Der Zustand wird bestimmt durch die Werte der Attribute und wird nur durch das Objekt selbst verändert. • Objekte werden von anderen Objekten durch Botschaften zur Ausführung von Zustandsänderungen angeregt. • Objekte sind Exemplare einer Klasse, die gemeinsame Attribute und Aktionen zusammenfasst. • Die genaue Datenstruktur und die Wirkungsweise der Methoden sind gekapselt. • Klassen stehen in Beziehung zueinander, es gibt Unterklassen und Oberklassen. • Eine Unterklasse unterscheidet sich von ihrer Oberklasse dadurch, dass sie mehr Merkmale aufweist, also eine Spezialisierung und damit eine Teilmenge beschreibt. • Die Unterklasse übernimmt oder erbt alle Attribute und Methoden der Oberklasse. • Sie kann die ererbten Methoden modifizieren und neue definieren. • Es gibt abstrakte Klassen, von denen keine Objekte ausgeprägt werden können. • Ein Objekt reagiert entsprechend seinem zur Laufzeit festgelegten Typ. Die Vererbung von Methoden und Attributen ist ein wesentliches Merkmal von objektorientierter Programmierung. 1.3 Programmaufbau 7 Ein weiteres wichtiges Merkmal ist die Möglichkeit wiederverwendbaren, weiterverwertbaren Programmcode zu erstellen. Dabei kann durch das Klassenkonzept der auf dem Rechner zur Verfügung stehende Vorrat an Datenstrukturen und Operationen ständig erweitert werden. Es ist in einer gut ausgestatteten Programmierumgebung nicht mehr nötig, das Rad zum x-ten Male neu zu erfinden, sondern man kann komplexe Strukturen und Operationen wie einfache Standardtypen benutzen. Um bei unserem Beispiel zu bleiben, kann man sagen, dass es nun möglich ist, ein Gerät aus fertigen Modulen zusammenzusetzen, ohne sich im Einzelnen um deren Aufbau kümmern zu müssen. Entsprechend vereinfacht sich die Wartung. Die objektorientierte Programmierung unterstützt sowohl die Anwendung von fertigen Programmbausteinen als auch deren Erstellung. Sie unterstützt modulares Vorgehen. 1.3 Programmaufbau Ein objektorientiertes Programm konstruiert (erzeugt) Objekte, die dann miteinander kommunizieren, indem sie eigene Methoden (Handlungsvorschriften) ausführen oder solche anderer Objekte aufrufen. In Java wird dieser Ablauf durch Aufruf der Methode main der Startklasse angestoßen. Das Programm selbst, der Programmtext oder Quelltext, besteht aus einer Reihe von Klassenvereinbarungen. Eine dieser Klassen, die Startklasse enthält eine Methode main. Das einfachste Programm ist also eine Klassenvereinbarung, die nur die Methode main enthält. Beispiel 3: Programmschablone public class Schablone { public static void main(String[] args) { // Hier wuerden die Anweisungen stehen ... } } cdrom:/buch/examples/java/Aufbau/Schablone.java Dieses Programm tut nichts. Wir wollen an dieser Stelle die Bedeutung der einzelnen Wörter nicht erklären und fassen dieses Beispiel als feste Schablone auf, in der der Name der Klasse und der Rumpf der Methode main verändert werden, um ein neues Programm zu erhalten. Der Rumpf der Methode main ist hier durch einen Kommentar ersetzt. Kommentare dienen zur Dokumentation und Erläuterung des Quelltextes und werden bei der Verarbeitung ignoriert. Kommentare können grundsätzlich an allen Stellen im Quellcode stehen, solange sie dort eindeutig als Kommentare zu identifizieren sind, also z.B. nicht innerhalb von Zeichenketten oder Namen. 8 Kapitel 1: Der objektorientierte Ansatz Es gibt drei Arten von Kommentaren: • Zeilenend-Kommentare: Beginnen mit // und enden am Zeilenende. Sie werden üblicherweise zum Erläutern von einzelnen Anweisungen verwendet. • Block-Kommentare: Stehen zwischen /* und */. Sie dienen meist zum Deaktivieren von Code-Bereichen, und werden selten zur Dokumentation verwendet. • Javadoc-Kommentare: Wie Block-Kommentare, beginnen jedoch mit /**. Sie werden für die aus dem Quellcode automatisch erzeugte Dokumentation verwendet und stehen daher normalerweise vor Konstrukten, die für die Verwendung des Codes durch andere Programme (oder Programmteile) geeignet sind, wie Klasse, Methoden oder Konstanten. Die JavadocKommentare haben eine interene Struktur, die bei den Quelltext-Konventionen4 beschrieben ist. Beispiel 4: Das folgende Programm gibt das Produkt von zwei Zahlen aus: public class Produkt { public static void main(String[] args) { int faktor1 = 2; int faktor2 = 3; System.out.println(faktor1 * faktor2); } } cdrom:/buch/examples/java/Aufbau/Produkt.java Ein einfaches Programm lässt sich durch folgendes Bild veranschaulichen: Wir zeichnen eine Klasse als ein Rechteck mit drei Fächern. Im ersten steht der Klassenname, im zweiten die Attribute und im dritten die Methoden. Abbildung 5: Aufbau einer Klasse Üblicherweise besteht ein Programm aus mehreren Klassen, von denen jede in einer eigenen Datei gespeichert wird. Beispiel 5: Die Klasse Preis1 Als Beispiel eines einfachen Programms vereinbaren wir eine Klasse, die einen Preis in Euro und Cent repäsentiert und eine Methode besitzt, die diesen Preis in Cent ausliest. Eine Testklasse konstruiert ein Preis-Objekt und ruft die Methode auf. Außerdem gibt es eine Methode, die einen Preis um einen anderen erhöht. 4 Siehe auch: Quelltext-Konventionen (S. 308) 1.3 Programmaufbau 9 Abbildung 6: Die Klasse TestPreis1 verwendet die Klasse Preis1 System.out.println(p1.getPreisInCent()); // p1 wird um einen Preis p2 erhoeht p1.erhoehe(p2); System.out.println(p1.getPreisInCent()); cdrom:/buch/examples/java/Klasse/TestPreis1.java Wir zeigen vom Programm hier nur den Methodenaufruf. Zusammengehörige Klassen werden in Paketen gruppiert. Der Paketname entspricht dabei einem Verzeichnis- (Ordner-)Namen im Dateisystem. Abbildung 7: Die Klassen TestPreis1 und Preis1 in einem Paket Die Beliebtheit und schnelle Verbreitung von Java wurde wesentlich durch eine Vielzahl vorhandener Standardpakete5 erhöht. Man kommt eigentlich nicht ohne fremde Pakete aus. So werden wesentliche Teile der Ein- und Ausgabe oder auch häufig gebrauchte Datentypen in Standardpaketen zur Verfügung gestellt. Der Import von Standard- oder selbst geschriebenen Paketen ist möglich und geschieht durch Angabe einer import- Klausel. Nur das Paket java.lang, welches die wichtigsten Standardklassen wie z.B. String und Math enthält, steht ohne Import zur Verfügung. Wir wollen hier nicht ins Detail6 gehen. Wir weisen jedoch darauf hin, dass wir für dieses Tutorial ein Paket simple bereit stellen, welches zwei Einzelpakete enthält. 5 6 Siehe auch: Standardpakete (S. 199) Siehe auch: Import von Paketen (S. 57) 10 Kapitel 1: Der objektorientierte Ansatz Beispiel 6: Import von Klassen Wir importieren die Klasse SimpleInput aus dem Paket simple.io und die Klasse ArrayList aus dem Standardpaket java.util. Zur Veranschaulichung verwenden wir folgendes Bild: Abbildung 8: Importieren von Klassen Ein Name für das aktuelle Paket ist nicht notwendig. 1.4 Java verwenden Java wurde von Sun Microsystems als eine Plattform-unabhängige, überall in gleicher Weise einsetzbare, objektorientierte Sprache entwickelt. Gleichzeitig mit dem Vorliegen der ersten Sprachdefinition 1995 wurde auch ein Entwicklungssytem (JDK - Java Development Kit) und eine umfangreiche Sammlung von Paketen oder Programmbibliotheken zur freien Verfügung gestellt. Diese Tatsache und die Möglichkeit, Programme einfach über das Internet aufzurufen, trugen zusammen mit dem allgemeinen Vormarsch der Objektorientierung zur rasanten Verbreitung bei. Da Java eine neue, rein objektorientierte Sprache ist, die auf Erfahrungen zurück greift, die mit C++ gemacht wurden, können wir Java als eine fortgeschrittene und fortschrittliche Sprache bezeichnen. Das aktuelle Java (offiziell Java 2 genannt) unterteilt sich in zwei Komponenten. Das J2RE - Java 2 Runtime Environment ist für die Ausführung von Programmen zuständig. Will man also ein Java Programm verwenden, so ist diese Komponente notwendig und ausreichend. Darüber hinaus gibt es zu Java noch eine ganze Reihe von Werkzeugen für die Erstellung von Java-Programmen, wie z.B. den Java-Compiler (javac), der den Programm-Quelltext in Bytecode übersetzt, welcher dann vom J2RE verwendet werden kann. Diese Werkzeuge sind selbst teilweise wieder Java-Programme und be- 1.4 Java verwenden 11 nötigen daher zur Ausführung das J2RE. Daher werden die Werkzeuge zusammen mit dem J2RE als J2SDK - Java 2 Software Development Kit zusammengefasst. Darüber hinaus gibt es Java noch in unterschiedlichen Varianten für verschiedene Gruppen von Zielgeräten. Normalerweise verwendet man die J2SE - Java 2 Standard Edition, jedoch stehen z.B. für stark eingeschränkte Endgeräte wie Handys oder PDAs die J2ME - Java 2 Micro Edition oder für Firmenanwendungen die J2EE - Java 2 Enterprise Edition zur Verfügung. Wir wollen uns hier lediglich mit der J2SE befassen, grundsätzlich lassen sich die vorgestellten Konzepte und Verfahren jedoch auch auf die anderen Platformen übertragen. Auf der beiliegenden CD finden sich auch die aktuelle Version (1.4.2) des J2SDK für Windows und Linux. Diese und neuere Versionen, wie z.B. die sich zur Zeit in Vorbereitung befindliche Version 1.5, können auch von der Java-Homepage7 heruntergeladen werden. Details zur Installation findet man im Anhang8 oder bei Sun9. 1.4.1 Umgebung Java Programme können in unterschiedlichen Umgebungen erstellt werden. Diese stellen drei Grundfunktionen zur Verfügung: • Eingeben bzw. Ändern (Editieren) des Quellcodes, • Übersetzen (Compilieren) des Quellcodes in Bytecode, • und Ausführen (Interpretieren) des Bytecodes. Die einfachste Umgebung ist die direkte Verwendung der mit dem J2SDK gelieferten Werkzeuge, wobei diese den ersten Schritt nicht explizit unterstützen. Das ist auch nicht nötig, denn zum Bearbeiten des Quellcodes ist generell jeder Editor geeignet. Es ist jedoch von Vorteil, wenn der Editor einen speziellen Modus für Java besitzt, so dass mindestens automatisches Einrücken und Syntax-Highlighting (Hervorherben von syntaktischen Elementen z.B. durch Farben) möglich ist. Das Übersetzen des Quellcodes in Bytecode erfolgt mit dem Programm javac. Javac ist der Compiler des J2SDK. Er übersetzt den Quellcode (z.B. Hello.java) in den "ausführbaren" Bytecode (Hello.class). Der erzeugte Bytecode kann dann auf jedem System, für das Java verfügbar ist, von der Virtuellen Maschine (JVM - Java Virtual Machine) ausgeführt werden. Die JVM wird mit dem Kommando java gestartet. Folgender Ablauf beschreibt den typischen Vorgang bei der Erstellung eines JavaProgramms: 7 http://java.sun.com/j2se/downloads.html Siehe auch: Installation des J2SDK (S. 273) 9 http://java.sun.com/j2se/1.4.2/install.html 8 12 Kapitel 1: Der objektorientierte Ansatz Abbildung 9: Entwicklungszyklus eine Java Programms Dieser wird üblicherweise in Zyklen wiederholt, bis das Programm das gewünschte Ergebnis liefert. Der Vorteil dieses Verfahrens liegt darin, dass es gleichermaßen auf praktisch allen Systemen verwendet werden kann, für die ein J2SDK zur Verfügung steht. Weiterhin behält man die volle Kontrolle darüber, was passiert, und kann die Ergebnisse (und Fehler) direkt beobachten. Zur Benutzung des fertigen Programm reicht es aus, die .class-Dateien (z.B. als Archiv) zu verteilen. Diese können dann auf allen Systemen, auf denen eine JVM zur Verfügung steht, ausgeführt werden. Details zur Verwendung des Java-Compilers und zum Aufruf der JVM finden sich wiederum im Anhang10. Statt des manuellen Aufrufs der Werkzeuge kann man auch sogenannte Integrierte Entwicklungsumgebungen (IDE - Integrated Development Environment) verwenden. Diese bieten neben herkömmlichen Editorfunktionen zusätzliche Unterstützung wie z.B. eingebaute Hilfe, automatische Vervollständigung, Fehlerkorrektur und vieles mehr. Das ist zwar prinzipiell ein großer Vorteil, birgt aber gerade für Einsteiger auch die Gefahr der Informationsüberflutung. Solche Entwicklungsumgebungen gibt es in großer Zahl sowohl im kommerziellen als auch im Open Source Umfeld. Auf der CD ist die aktuelle Version von Eclipse für Windows und Linux enthalten. Es sei noch darauf hingewiesen, dass auch die meisten Entwicklungsumgebungen das J2SDK benötigen. Sie bringen meist keinen eigenen Compiler oder gar eine eigene JVM mit. Die Installation des J2SDK ist also auch beim Einsatz einer IDE meist nötig. Damit die Beispiele dieses Tutorials möglichst einfach ausprobiert werden können, haben wir ein Programm in die HTML-Version integriert, die es erlaubt die Beispiele direkt zu starten. Das Programm JEEE ermöglicht es die Beispiele auszuführen (mit Benutzerinteraktion, sofern das vom Beispiel vorgesehen ist) oder diese auch zu verändern. Voraussetzung ist lediglich die Installation des J2SDK. 10 Siehe auch: J2SDK (S. 273) 1.4 Java verwenden 13 Details zum Setup und der Verwendung von JEEE finden sich wiederum im Anhang11. 1.4.2 Syntaxdiagramme Eine Programmiersprache hat feste syntaktische Regeln. Diese sind meist nicht einfach durch Text zu beschreiben, und eine formale textuelle Beschreibung ist nicht gut zu verstehen. Daher verwenden wir Syntaxdiagramme zur Beschreibung. Syntaxdiagramme definieren Schablonen, die durch Ausfüllen zu fertigen Programmen (oder Programmteilen) führen. Folgendes Diagramm zeigt einige der wichtigsten Eigenschaften: Die abgerundeten Elemente sind sogenannte Terminale, die einen festen, exakt so in das Programm zu übernehmenden Text darstellen. Die eckigen Elemente sind die Nicht-Terminale, die durch etwas anderes ersetzt werden müssen. Was das genau ist, ist jeweils an anderer Stelle beschrieben, die Bezeichnung gibt aber einen Hinweis. Im obigen Bild ist also die "0" ein Terminal, und "1..9" bzw. "0..9" Nicht-Terminale (diese wären dann gemäß einem anderen Syntaxdiagramm durch die entsprechenden Ziffern zu ersetzen). Syntaxdiagramme werden von links oben, den durchgezogenen Linien folgend, von links nach recht und von oben nach unten durchlaufen. Gestrichelte Linien werden in entgegengesetzter Richtung durchlaufen. Kann man an einer Stelle mehreren Wegen folgen, so ist einer davon zu wählen. Erreicht man das Ende der Linie (ganz rechts) so ist dieses Syntaxdiagramm vollständig durchlaufen. Bei Durchlaufen des obigen Diagramms beginnt man nun links oben, und muss sich dann gleich entscheiden. Man kann der Linie nach rechts folgen, dann kommt man an das Terminal "0". Folgt man der Linie dann weiter, so kommt man unweigerlich an das Ende des Diagramms (an der Kreuzung darf man ja nur nach rechts, da nur gestrichelte Linien nach links durchlaufen werden). Eine Dezimalzahl kann also eine einzelne "0" sein. 11 Siehe auch: JEEE (S. 282) 14 Kapitel 1: Der objektorientierte Ansatz Alternativ kann man anfangs auch der Linie nach unten folgen. Dann kommt man an das Nicht-Terminal "1..9" welches für eine der Ziffern 1 bis 9 steht. Dannach kann man der Linie weiter bis ans Ende folgen. D.h. die Ziffern 1 bis 9 sind auch "Dezimalzahlen". Statt bis an das Ende des Diagramms zu gehen kann man aber auch die Abzweigung nach unten nehmen. Hier kommt man an das Nicht-Terminal "0..9". Von dort aus kann man entweder weiter bis an das Ende des Diagramms, oder man geht nach unten, folgt dann der gestrichelten Linie zunächst nach links und dann noch oben, und kommt dann wieder zum Nicht-Terminal "0..9" und ist damit wieder an derselben Stelle wie oben. Man kann also die "Schleife" beliebig oft durchlaufen. Dies bedeutet also, dass eine Ziffer 1 bis 9, gefolgt von keiner, einer oder beliebig vielen Ziffern 0 bis 9 eine Dezimalzahl darstellt. Man beachte, dass Zahlen die mit einer "0" beginnen und nicht nur aus diesem einen Zeichen bestehen keine Dezimalzahlen sind. Diese werden als Oktal- bzw. Hexadezimalzahlen interpretiert. 1.4.3 Das Hilfspaket simple In Java gibt es verschiedene Wege Daten einzulesen. Diese werden im Abschnitt Ein-/Ausgabe12 behandelt. Allerdings sind diese Möglichkeiten für die normale Verwendung vorgesehen und erfordern daher komplexere Vorgänge, insbesondere z.B die Fehlerbehandlung. Da dies im Moment noch nicht so wichtig für die Programme ist und sie nur unnötig verkompliziert, und damit vom Wesentlichen ablenkt, werden wir in diesem Tutorial eine Hilfsbibliothek verwenden, die es erlaubt, die Eingabe (und einiges andere) vereinfacht vorzunehmen. Die Bibliothek simple stellt dazu Möglichkeiten zur Verfügung Daten (Zahlen, Wörter, Zeilen) von der Tastatur einzulesen, oder auch Zufallszahlen zu erzeugen. Eine genauere Beschreibung der Bibliothek und Details zur Verwendung und zur Einbindung finden sich im Anhang13. Wenn die Beispiele allerdings mit JEEE über die HTML-Version des Tutorials gestartet werden, braucht man sich darum erstmal nicht zu kümmern. 1.5 Gestaltung und Formatierung von Java-Quelltext In kleinen Programmen mag es egal sein, in welcher Form der Quelltext geschrieben wird, wie weit man z.B. einrückt, wo Kommentare stehen etc., aber in einem großen und zeitlich ausgedehnteren Projekt ist es wichtig, dass der Programmcode auch von anderen Programmierern und auch nach Jahren noch leicht lesbar und nachvollziehbar ist. 12 13 Siehe auch: Ein-/Ausgabe (S. 237) Siehe auch: Die Bibliothek: simple (S. 284) 1.5 Gestaltung und Formatierung von Java-Quelltext 15 Deshalb halten wir uns an Formatierungsregeln, die in fast allen Punkten der Java Coding Convention14 von Sun Microsystems entnommen sind. Im Einzelnen werden wir die Konventionen im Text durch in dieser Weise gekennzeichnete Absätze einführen. Die Gestaltungsregeln sind im Anhang15 zusammengefasst. 14 15 http://java.sun.com/docs/codeconv/ Siehe auch: Quelltextkonventionen (S. 307) http://www.springer.com/978-3-540-23134-9