Algorithmik 1 M. Phillipsen, H. Stoyan, M. Stamminger Friedrich-Alexander-Universität Erlangen-Nürnberg Informatik 2/8/9 Kapitel 7 - Java-Details 7.1 7.2 7.3 7.4 7.5 Codier-Regeln für Java Vererbung am Beispiel Graphische Oberfläche Unter der Lupe Was geht schief? Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-2 M. Stamminger 7.1 Codier-Regeln für Java Wenn Sie wirklich wollen, dann könnten Sie ihre Programme schreiben, ohne jemals die Return-Taste zu drücken. Die Anordnung in Zeilen ist nur für den menschlichen Leser. Ebenso ist das Einrücken aus Sicht der Übersetzers völlig unnötig. Es dient lediglich dem besseren Verständnis, weil man auf einen Blick erkennt, wo z.B. eine Schleife beendet ist. Æ Derartige Regeln heißen Codier-Regeln. In diesem Abschnitt besprechen wir übliche Codier-Regeln für Java. Bitte einhalten! Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-3 M. Stamminger 7.1 Codier-Regeln für Java Mehr Motivation Im Durchschnitt fallen 80% der Kosten eines Programms während der Wartung an. Kaum ein Programm wird über seine ganze Lebensdauer vom ursprünglichen Autor betreut. Codier-Regeln verbessern die Lesbarkeit von Software; neuer Code ist leichter zu begreifen; die Kosten der Wartung werden gesenkt. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-4 M. Stamminger 7.1 Codier-Regeln für Java Codier-Regeln für Dateinamen Quellcode-Dateien haben den Suffix .java ByteCode-Dateien haben den Suffix .class Maximal eine öffentliche Klasse pro Quelldatei. Ist eine öffentliche Klasse namens X im Quellcode, dann muss die Quellcode-Datei X.java heißen. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-5 M. Stamminger 7.1 Codier-Regeln für Java Codier-Regeln für Programmdateien Mehr als 2.000 Zeilen sollte keine Programmdatei lang sein Leerzeilen zur optischen Trennung Generelle Struktur jeder Programmdatei 1. Anfangskommentar /* /* ** Klassenname Klassenname ** ** Versionsangabe Versionsangabe ** ** Datum Datum ** ** Copyright-Angabe, Copyright-Angabe, Autoren Autoren */ */ 2. package und import-Anweisung 3. class und interface Deklarationen Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-6 M. Stamminger 7.1 Codier-Regeln für Java Codier-Regeln für class und interface Deklarationen Generelle Struktur jeder class und interface Deklaration 1. externer Kommentar /** … */ 2. class … { oder interface … { 3. interner Kommentar 4. statische Variablen in der Reihenfolge public, protected, (package), private 5. Instanzvariablen in der Reihenfolge public, protected, (package), private 6. Konstruktoren 7. Methoden nach Funktionalität gruppiert unabhängig von der Sichtbarkeit Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-7 M. Stamminger 7.1 Codier-Regeln für Java Programmzeilenformatierung (1) Einrückungen sollten in 4er-Schritten erfolgen Keine Zeile sollten mehr als 80 Zeichen enthalten, Kommentarzeilen nicht mehr als 70 Zeichen Wenn die Zeile zu lang wird, möglichst an folgenden Stellen umbrechen: y nach einem Komma int a,| b y vor einem Operator 47 |+ 11 y möglichst gemäß der Bindungsstärke Die Folgezeile wird so weit eingerückt wie der Ausdruck „auf gleicher Schachtelungsebene“ in der vorhergehenden Zeile. Wenn dabei zu tief eingerückt würde, dann einen 8er-Schritt gegenüber der vorherigen Zeile einrücken. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-8 M. Stamminger 7.1 Codier-Regeln für Java Programmzeilenformatierung (2) someMethod1(longExpression1, someMethod1(longExpression1, longExpression2, longExpression2, longExpression3, longExpression3, longExpression4); longExpression4); var var == someMethod(longExpression1, someMethod(longExpression1, someMethod2(longExpression2, someMethod2(longExpression2, longExpression3)); longExpression3)); longName1 longName1 == longName2 longName2 ** (longName3 (longName3 ++ longName4 longName4 -- longName5) longName5) ++ 44 ** longName6; longName6; //obige //obige Formatierung Formatierung ist ist besser besser als: als: longName1 longName1 == longName2 longName2 ** (longName3 (longName3 ++ longName4 longName4 -- longName5) longName5) ++ 44 ** longName6; longName6; Leerzeichen zwischen Operator und Operanden Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-9 M. Stamminger 7.1 Codier-Regeln für Java Programmzeilenformatierung (3) //übliche //übliche Formatierung: Formatierung: someMethod(int someMethod(int anArg, anArg, Object Object anotherArg, anotherArg, String String yetAnotherArg, yetAnotherArg, Object Object andStillAnother) andStillAnother) {{ ... ... }} //wenn //wenn zu zu tief tief eingrückt eingrückt werden werden würde würde private private static static synchronized synchronized veryLongMethodName(int veryLongMethodName(int anArg, anArg, Object Object anotherArg, anotherArg, String String yetAnotherArg, yetAnotherArg, Object Object andStillAnotherArg) andStillAnotherArg) {{ ... ... }} mit „normaler“ Einrückregel, würde es in Folgezeile hier weitergehen. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-10 M. Stamminger 7.1 Codier-Regeln für Java Programmzeilenformatierung (4) Werden Bedingungen von if-Anweisungen zu lang, stets mindestens 8 Schritte einrücken //schlechte //schlechte Formatierung: Formatierung: if if ((condition1 ((condition1 && && condition2) condition2) || || (condition3 (condition3 && && condition4) condition4) ||!(condition5 ||!(condition5 && && condition6)) condition6)) {{ doSomethingAboutIt(); doSomethingAboutIt(); }} //Verwenden //Verwenden Drucker Drucker o. o. //Terminal //Terminal falsche falsche //Zeilenlänge, //Zeilenlänge, dann dann ist ist //Rumpf //Rumpf leicht leicht zu zu //übersehen! //übersehen! //besser: //besser: if if ((condition1 ((condition1 && && condition2) condition2) || || (condition3 (condition3 && && condition4) condition4) ||!(condition5 ||!(condition5 && && condition6)) condition6)) {{ doSomethingAboutIt(); doSomethingAboutIt(); }} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-11 M. Stamminger 7.1 Codier-Regeln für Java Programmzeilenformatierung (5) Bedingung wahr? dann Formatierung des Fragezeichen-Operators:erster Ausdruck : sonst zweiter Ausdruck. Bedingung in Klammern //je //je nach nach Geschmack: Geschmack: alpha alpha == (aLongBooleanExpression) (aLongBooleanExpression) ?? (int) (int) beta beta :: gamma++; gamma++; alpha alpha == (aLongBooleanExpression) (aLongBooleanExpression) ?? (int) (int) beta beta :: gamma++; gamma++; alpha alpha == (aLongBooleanExpression) (aLongBooleanExpression) ?? (int) (int) beta beta :: gamma++; gamma++; Leerzeichen nach expliziter Typwandlung Nie Leerzeichen bei unären Operatoren Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-12 M. Stamminger 7.1 Codier-Regeln für Java Kommentare In Java unterscheidet man zwischen Kommentaren zur Implementierung und Kommentaren zur Dokumentation. y Implementierungskommentare werden mit // oder /*…*/ geschrieben. à Beschreiben Implementierungsgedanken à Vor-/Nachbedingungen, Invarianten à Auskommentieren von Code, der nicht mehr gebraucht wird y Dokumentationskommentare werden durch /**…*/ gekennzeichnet. à Beschreibung für Entwickler, die die Klasse benutzen wollen. à Funktionsweise, Bedeutung der Argumente von Methoden, … y Das Werkzeug javadoc kann Dokumentationskommentare extrahieren und html-Seiten generieren, wie Sie diese aus der Dokumentation der StandardBibliotheken kennen. Redundante Kommentare vermeiden Daumenregel: Wenn ein Programmstück so trickreich ist, dass man als Programmierer einen Implementierungskommentar als unbedingt notwendig betrachtet, dann besser den Code klarer schreiben! Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-13 M. Stamminger 7.1 Codier-Regeln für Java Dokumentationskommentar am Beispiel (1) /** /** ** Returns Returns an an Image Image object object that that can can then then be be painted painted ** on on the the screen. screen. ** <p> <p> ** The The name name argument argument is is aa specifier specifier that that …… ** ** @param @param url url an an absolute absolute URL URL giving giving the the base base location location ** name name the the location location of of the the image, image, relative relative to to url url ** @return the image at the specified URL @return the image at the specified URL ** @see Image @see Image */ */ public public Image Image getImage(URL getImage(URL url, url, String String name) name) {{ try try {{ return return getImage(new getImage(new URL(url, URL(url, name)); name)); }} catch catch (MalformedURLException (MalformedURLException e) e) {{ return return null; null; }} }} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-14 M. Stamminger 7.1 Codier-Regeln für Java Dokumentationskommentar am Beispiel (2) getImage getImage public public Image Image getImage(URL getImage(URL url, url, String String name) name) Returns Returnsan anImage Imageobject objectthat thatcan canthen thenbe bepainted paintedon onthe thescreen. screen. The Theargument argumentisisaaspecifier specifierthat that… … Parameters: Parameters: url url--an anabsolute absoluteURL URLgiving givingthe thebase baselocation location name name--the thelocation locationofofthe theimage, image,relative relativetotourl url Returns: Returns: the theimage imageatatthe thespecified specifiedURL URL See SeeAlso: Also: Image Image Mehr Informationen unter: http://java.sun.com/j2se/javadoc/ Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-15 M. Stamminger 7.1 Codier-Regeln für Java Deklarationen (1) Eine Deklaration pro Zeile, vermeide Komma-Form (int a,b;) Initialisierung möglichst unmittelbar an der Deklarationsstelle Deklarationen am Anfang eines Blocks {…}, also nicht warten, bis die Variable benötigt wird. Nur Laufvariablen von for-Schleifen werden nicht an den Anfang des umgebenden Blocks gezogen. In der Klassendeklaration Leerzeichen vor { Beispiel: class Sample extends Object { Leerzeichen bei Methodendeklaration gemäß foo(int i, int j) { } immer in einer eigenen Zeile, so weit eingerückt wie Eröffnung. Leerzeile zwischen 2 Methodendeklarationen Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-16 M. Stamminger 7.1 Codier-Regeln für Java Deklarationen (2) Leerzeichen ohne Leerzeichen class class Sample Sample extende extende Object Object {{ int int ivar; ivar; int int ivar2; ivar2; Sample(int Sample(int i, i, int int j) j) {{ ivar ivar == i; i; ivar ivar == j; j; }} int int emptyMethod() emptyMethod() {} {} ... ... }} } in eigener Zeile, eingerückt wie class Leerzeichen Leerzeile } in eigener Zeile, eingerückt wie Sample Leerzeile ausnahmesweise } in gleicher Zeile Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-17 M. Stamminger 7.1 Codier-Regeln für Java Anweisungen (1) Nur eine Anweisung pro Zeile { steht am Ende der Zeile derjenigen Anweisung, die Block öffnet return: Rückgabewert if if (condition) (condition) {{ nicht in Klammern () statements; statements; if-Anweisungen: }} Stets {} verwenden, auch if if (condition) (condition) {{ statements; wenn nur eine Anweisung statements; }} else in einem Zweig ist. else {{ statements; statements; }} if if (condition) (condition) {{ statements; statements; }} else else if if (condition) (condition) {{ statements; statements; }} else else {{ statements; statements; }} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-18 M. Stamminger 7.1 Codier-Regeln für Java Anweisungen (2) Schleifen: Nicht mehr als 3 Variablen gleichzeitig verändern. for for (initialization; (initialization; condition; condition; update) update) {{ statements; statements; }} Leerzeichen //leere //leere Schleife: Schleife: for for (initialization; (initialization; condition; condition; update); update); while while (condition) (condition) {{ statements; statements; }} do do {{ statements; statements; }} while while (condition); (condition); Leerzeichen zwischen Schlüsselwort und ( Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-19 M. Stamminger 7.1 Codier-Regeln für Java Anweisungen (3) switch-Anweisung: switch switch (condition) (condition) {{ case case ABC: ABC: statements; statements; /* /* fällt fällt durch durch */ */ case DEF: case DEF: statements; statements; break; break; case case XYZ: XYZ: statements; statements; break; break; default: default: statements; statements; break; break; }} Kommentar, wenn wirklich „Durchrauschen“ in den nächsten Fall beabsichtigt ist. Dann keine Leerzeile. Leerzeile zwischen zwei Fällen. default-Fall immer vorsehen. Redundantes break schützt bei nachträglich ergänzten neuen Fällen. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-20 M. Stamminger 7.1 Codier-Regeln für Java Anweisungen (4) try-Anweisung: try try {{ statements; statements; }} catch catch (ExceptionClass (ExceptionClass e) e) {{ statements; statements; }} finally finally {{ statements; statements; }} ggf. ohne finally. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-21 M. Stamminger 7.1 Codier-Regeln für Java Namensgebung (1) Alle Namen sollten so gewählt werden, dass sie schon beim Lesen erklären, was sie bedeuten und welche Funktion sie im Programm haben. Solche Namen heißen mnemonische Namen. y Keine winzigen, erst recht keine einbuchstabigen Namen verwenden y Ausnahmen: à Laufvariablen von Schleifen (typisch: i, j, k) à temporäre „Wegwerf“-Variablen, die nur an einer Stelle benutzt werden, z.B. um die Werte zweier Variable zu vertauschen. Paketnamen sollten nur aus Kleinbuchstaben bestehen. Dabei nimmt man üblicherwiese „seine“ Domain rückwärts als Präfix: Beispiel: de.uni-erlangen.informatik.i9.algo1 Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-22 M. Stamminger 7.1 Codier-Regeln für Java Namensgebung (2) Klassennamen und Schnittstellennamen sollten Substantive sein und mit einem Großbuchstaben beginnen. Bei zusammengesetzten Substantiven beginnt jedes neue Wort wieder mit einem Großbuchstaben. Beispiele: class Rational, class BibliotheksBenutzer Methodennamen sind Verben und beginnen mit einem Kleinbuchstaben. Bei zusammengesetzten Verben beginnt jedes neue Wort mit einem Großbuchstaben. Beispiele: run(), runFast() Variablennamen fangen mit Kleinbuchstaben an (weder _ noch $). Bei zusammengesetzten Substantiven beginnt jedes neue Wort wieder mit einem Großbuchstaben. Namen konstanter Werte nutzen ausschließlich Großbuchstaben. Bei Zusammensetzung _ zur Worttrennung verwenden. Beispiele: MIN_WIDTH, MAX_LENGTH Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-23 M. Stamminger 7.1 Codier-Regeln für Java Code-Klarheit (1) Instanzvariablen sollten nur mit wirklich gutem Grund öffentlich zugänglich sein. Lieber set() und get() Methoden verwenden, die den Wert der Instanzvariablen setzen bzw. zurückliefern. Niemals ein Objekt verwenden, um (statische) Klassenvariablen oder (statische) Klassenmethode aufzurufen. Lieber Klassenname.name Keine Kettenzuweisungen machen: a = b = c; Keine Zuweisung verwenden, wo sie mit einer Vergleichsoperation verwechselt werden kann: if (a = d) { … Lieber: if ((a = d) == true) { … Auf eingebettete Zuweisungen verzichten d = (a = b + c) + r Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-24 M. Stamminger 7.1 Codier-Regeln für Java Code-Klarheit (2) Konstante Werte sollten (fast) nie explizit als Literale im Code stehen. Stattdessen Konstante mit Namen deklarieren und den Namen im Code nutzen. Im Zweifel zu viel Klammern if (a == b && c == d) Lieber: if ((a == b) && (c == d)) Nicht jedem Leser des Programms sind die Präzedenzregeln klar. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-25 M. Stamminger 7.2 Vererbung am Beispiel Festkörperbeispiel (1) Kugel Festkörper Quader Zylinder mit abstrakter Klasse: public public abstract abstract class class Festkoerper Festkoerper {{ public public final final static static float float PI PI == 3.1415926; 3.1415926; public public abstract abstract double double oberflaeche(); oberflaeche(); public abstract double volumen(); public abstract double volumen(); }} oder mit Interface: public public interface interface Festkoerper Festkoerper {{ public public final final static static float float PI PI == 3.1415926; 3.1415926; public public double double oberflaeche(); oberflaeche(); public public double double volumen(); volumen(); }} Beides ist sinnvoll, weil die Klasse nur abstrakte Methoden und Konstanten deklariert. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-26 M. Stamminger 7.2 Vererbung am Beispiel Festkörperbsp. (2) Zustand Oberfläche Quader Quader: Länge, Breite, Höhe 2·(Länge·Breite + Länge·Höhe + Breite·Höhe) Volumen Länge·Breite·Höhe Zylinder Radius, Höhe 2·π·Radius· π·Radius²·Höhe (Radius + Höhe) Kugel 4·π·Radius² Radius 4/3·π·Radius3 public public class class Quader Quader implements implements Festkoerper Festkoerper {{ private private double double laenge, laenge, breite, breite, hoehe; hoehe; public public double double oberflaeche() oberflaeche() {{ return return 22 ** (laenge (laenge ** breite breite ++ laenge laenge ** hoehe hoehe ++ breite breite ** hoehe); hoehe); }} public public double double volumen() volumen() {{ return return laenge laenge ** breite breite ** hoehe; hoehe; }} ...} ...} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-27 M. Stamminger 7.2 Vererbung am Beispiel Festkörperbsp. (3) Zustand Oberfläche Quader Länge, Breite, Höhe 2·(Länge·Breite + Länge·Höhe + Breite·Höhe) Volumen Länge·Breite·Höhe Zylinder Radius, Höhe 2·π·Radius· π·Radius²·Höhe (Radius + Höhe) Kugel 4·π·Radius² Radius 4/3·π·Radius3 Zylinder: public public class class Zylinder Zylinder implements implements Festkoerper Festkoerper {{ private private double double radius, radius, hoehe; hoehe; public public double double volumen() volumen() {{ return return PI PI ** radius radius ** radius radius ** hoehe; hoehe; }} public public double double oberflaeche() oberflaeche() {{ return return 22 ** PI PI ** radius radius ** (radius (radius ++ hoehe); hoehe); }} ...} ...} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-28 M. Stamminger 7.2 Vererbung am Beispiel Festkörperbsp. (4) Zustand Oberfläche Quader Länge, Breite, Höhe 2·(Länge·Breite + Länge·Höhe + Breite·Höhe) Volumen Länge·Breite·Höhe Zylinder Radius, Höhe 2·π·Radius· π·Radius²·Höhe (Radius + Höhe) Kugel 4·π·Radius² Radius 4/3·π·Radius3 Kugel: public public class class Kugel Kugel implements implements Festkoerper Festkoerper {{ private private double double radius; radius; public public double double volumen() volumen() {{ return return 4.0/3.0 4.0/3.0 ** PI PI ** radius radius ** radius radius ** radius; radius; }} public public double double oberflaeche() oberflaeche() {{ return return 44 ** PI PI ** radius radius ** radius; radius; }} ...} ...} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-29 M. Stamminger 7.2 Vererbung am Beispiel Festkörperbeispiel (5) Festkoerper Festkoerper ff == new new Kugel(); Kugel(); System.out.println(f.volumen()); System.out.println(f.volumen()); ff == new new Zylinder(); Zylinder(); System.out.println(f.volumen()); System.out.println(f.volumen()); Abhängig vom dynamischen Typ des Objekts (von welchem Typ ist f zur Laufzeit?) wird die zugehörige konkrete Implementierung aufgerufen. Variable vom Typ einer Schnittstelle (oder einer abstrakten Klasse). Jede Instanz muss die Methoden der Schnittstelle implementieren. bei statischen Methoden und Instanzvariablen gelten andere Regeln Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-30 M. Stamminger 7.2 Vererbung am Beispiel Mehrfachvererbung eingeschränkt auch in Java interface interface BaseColors BaseColors {{ int int RED RED == 1; 1; int int GREEN GREEN == 2; 2; int int BLUE BLUE == 4; 4; }} interface interface RainbowColors RainbowColors extends extends BaseColors BaseColors {{ int int YELLOW YELLOW == 3; 3; int int ORANGE ORANGE == 5; 5; int INDIGO = 6; int INDIGO = 6; int int VIOLET VIOLET == 7; 7; }} interface interface PrintColors PrintColors extends extends BaseColors BaseColors {{ int int YELLOW YELLOW == 8; 8; int == 16; int CYAN CYAN 16; int int MAGENTA MAGENTA == 32; 32; }} interface interface LotsOfColors LotsOfColors extends extends RainbowColors, RainbowColors, PrintColors PrintColors {{ int int FUCHSIA FUCHSIA == 17; 17; …… }} OK, solange nicht auf YELLOW zugegriffen wird. Fehler auch wenn jeder Pfad YELLOW auf den selben Wert setzen würde Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-31 M. Stamminger 7.2 Vererbung am Beispiel Festkörperbeispiel (6) public public class class Kugel Kugel implements implements Festkoerper, Festkoerper, LotsOfColors LotsOfColors {{ ... ... int int color color == RED; RED; //alles //alles ok ok Kugel(int Kugel(int color) color) {{ if if ((color ((color << MIN_COLOR) MIN_COLOR) || || (color (color >> MAX_COLOR)) MAX_COLOR)) {{ this.color this.color == YELLOW; YELLOW; //Fehler //Fehler zur zur Übersetzungszeit Übersetzungszeit }} else else {{ this.color this.color == color; color; }} }} }} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-32 M. Stamminger 7.3 Graphische Oberfläche SWING erlaubt das Gestalten von graphischen Benutzeroberflächen mit Knöpfen, Menüs, Schiebereglern usw. in einer plattformunabhängigen Weise für MS Windows/NT, MacOS, Solaris, Linux, u.a. Das Erscheinungsbild wird an die jeweilige Plattform angepasst. Wir benutzen die Komponenten aus der SWING-Bibliothek (z. B. JButton), nicht die Komponenten aus der AWT-Bibliothek (also nicht Button), müssen aber auch auf Klassen in der AWT- Bibliothek (z. B. GridBagLayout) zurückgreifen. Plan für das Lernen der Grundkonzepte: y Welche einfachen graphischen Interaktionskomponenten gibt es? y Wie werden sie auf dem Bildschirm angezeigt und angeordnet? y Wie reagieren sie auf Eingaben und Benutzung? Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-33 M. Stamminger Interaktionskomponenten (1) 7.3 Graphische Oberfläche JButton Knopf, Schaltfläche JCheckBox Ankreuzfeld JFrame Rahmen mit Titelbalken etc. JLabel Beschriftung JList Auswahlliste JPanel Behälter zum Gruppieren und Anordnen v. Komponenten Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-34 M. Stamminger Interaktionskomponenten (2) 7.3 Graphische Oberfläche JRadioButton Umschaltknopf ButtonGroup Mehrere Knöpfe, von denen nur einer gedrückt ist JScrollbar Verschiebebalken JSlider Schieberegler JTextField JTextArea Editierbares einzeiliges bzw. mehrzeiliges Textfeld Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-35 M. Stamminger 7.3 Graphische Oberfläche Gedanklicher Aufbau eines Fensters: Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-36 M. Stamminger 7.3 Graphische Oberfläche Aufbau eines Fensters in der Datenstruktur: Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-37 M. Stamminger 7.3 Graphische Oberfläche Das erste Swing-Programm (1) import import java.awt.*; java.awt.*; import import java.awt.event.*; java.awt.event.*; import import javax.swing.*; javax.swing.*; public public class class RahmenMitKnopf RahmenMitKnopf {{ public public static static void void main main (String (String args[]) args[]) {{ JFrame JFrame rr == new new JFrame("RahmenMitKnopf"); JFrame("RahmenMitKnopf"); Komponenten, die später in den Rahmen eingefügt werden, werden i.A. zeilenweise von links nach rechts im Fenster angeordnet. Rahmengröße richtet sich nach Größe der Komponenten JButton JButton kk == new new JButton("Knoepfle"); JButton("Knoepfle"); k.SetToolTipText("tut k.SetToolTipText("tut nichts"); nichts"); //Hinweistext //Hinweistext r.getContentPane().add(k); r.getContentPane().add(k); Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-38 M. Stamminger 7.3 Graphische Benutzeroberfläche Das erste Swing-Programm (2) Funktionalität wird in Objekten gekapselt Hier: beim Schließen des Fensters soll sich das Programm beenden class class MyCloser MyCloser extends extends WindowAdapter WindowAdapter {{ public public void void windowClosing(WindowEvent windowClosing(WindowEvent e) e) {{ System.exit(0); System.exit(0); }} }} Separate Klassendefinition für jedes mögliche Ereignis ist lästig. "Anonyme innere Klassen" helfen, s.u. ... ... JFrame JFrame rr == new new JFrame("RahmenMitKnopf"); JFrame("RahmenMitKnopf"); r.addWindowListener(new r.addWindowListener(new MyCloser()); MyCloser()); ... ... Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-39 Wenn der Rahmen das Ereignis windowClosing sieht, dann wird die entspr. Methode des Objekts myCloser aufgerufen. M. Stamminger Das erste Swing-Programm (3) 7.3 Graphische Oberfläche import import java.awt.*; java.awt.*; import import java.awt.event.*; java.awt.event.*; import import javax.swing.*; javax.swing.*; public public class class RahmenMitKnopf RahmenMitKnopf {{ public public static static void void main main (String (String args[]) args[]) {{ JFrame JFrame rr == new new JFrame("RahmenMitKnopf"); JFrame("RahmenMitKnopf"); r.addWindowListener(new r.addWindowListener(new WindowAdapter() WindowAdapter() {{ public public void void windowClosing(WindowEvent windowClosing(WindowEvent e) e) {{ System.exit(0); System.exit(0); }} }); //Anonyme }); //Anonyme Innere Innere Klasse! Klasse! JButton JButton kk == new new JButton("Knoepfle"); JButton("Knoepfle"); k.setToolTipText("tut k.setToolTipText("tut nichts"); nichts"); //Hinweistext //Hinweistext r.getContentPane().add(k); r.getContentPane().add(k); r.pack(); r.pack(); r.setVisible(true); r.setVisible(true); }} }} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-40 M. Stamminger 7.3 Graphische Oberfläche Die Lage der Komponenten im Fenster wird nur relativ spezifiziert. Ändert sich die Größe des Fensters, wird diese Größenänderung an alle Komponenten des Fensters weitergegeben. Bisher: Fließplatzierer („FlowLayout“): Komponenten werden nacheinander von links nach rechts im Fenster angezeigt. add(e), add(e,i), remove(e), remove(i), removeAll()… Weitere Platzierer: y y y y Gitteranordnung (2D-Raster): Einfassungsanordnung: Schachtelanordnung: Variable Rasteranordnung: GridLayout BorderLayout BoxLayout GridBagLayout Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-41 M. Stamminger 7.3 Graphische Oberfläche Gitteranordnung, GridLayout (1) Einer der Konstruktoren: GridLayout(int zeilen, int spalten) Dieser legt ein Gitter mit der angegebenen Zeilen-/Spaltenzahl an. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-42 M. Stamminger 7.3 Graphische Oberfläche Gitteranordnung, GridLayout (2) import import java.awt.*; java.awt.*; import import java.awt.event.*; java.awt.event.*; import import javax.swing.*; javax.swing.*; class class Gitteranordnung{ Gitteranordnung{ public public static static void void main(String[] main(String[] args) args) {{ JFrame JFrame rr == new new JFrame("Gitter JFrame("Gitter -- Anordnung"); Anordnung"); JPanel JPanel pp == new new JPanel(new JPanel(new GridLayout(2,3)); GridLayout(2,3)); p.add(new p.add(new JButton("Knopf1")); JButton("Knopf1")); p.add(new p.add(new JButton("Knopf2")); JButton("Knopf2")); p.add(new p.add(new JButton("3")); JButton("3")); p.add(new p.add(new JButton("Knopf JButton("Knopf mit mit langem langem Text")); Text")); p.add(new p.add(new JButton("Knopf5")); JButton("Knopf5")); r.getContentPane().add(p); r.getContentPane().add(p); r.pack(); r.pack(); r.setVisible(true); r.setVisible(true); }} }} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-43 M. Stamminger 7.3 Graphische Oberfläche Einfassungsanordnung, BorderLayout (1) maximal 5 Komponenten werden angeordnet: in der Mitte und in jeder der vier Himmelsrichtungen. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-44 M. Stamminger 7.3 Graphische Oberfläche Einfassungsanordnung, BorderLayout (2) class class Einfassung Einfassung {{ public public static static void void main( main( String[] String[] args args )) {{ JFrame JFrame ff == new new JFrame("Gitter JFrame("Gitter -- Anordnung"); Anordnung"); JPanel JPanel pp == new new JPanel(new JPanel(new BorderLayout()); BorderLayout()); f.getContentPane().add(p); f.getContentPane().add(p); JButton JButton bb == new new JButton("Norden"); JButton("Norden"); p.add(b, BorderLayout.NORTH); p.add(b, BorderLayout.NORTH); bb == new new JButton("Sueden"); JButton("Sueden"); p.add(b, p.add(b, BorderLayout.SOUTH); BorderLayout.SOUTH); bb == new new JButton("Westen"); JButton("Westen"); p.add(b, p.add(b, BorderLayout.WEST); BorderLayout.WEST); bb == new new JButton("Osten"); JButton("Osten"); p.add(b, p.add(b, BorderLayout.EAST); BorderLayout.EAST); bb == new new JButton("Mitte"); JButton("Mitte"); p.add(b, p.add(b, BorderLayout.CENTER); BorderLayout.CENTER); f.pack(); f.pack(); f.setVisible( f.setVisible( true true ); ); }} }} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-45 M. Stamminger 7.3 Graphische Oberfläche Schachtelanordnung, BoxLayout Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-46 M. Stamminger 7.3 Graphische Oberfläche Variable Rasteranordnung, GridBagLayout Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-47 M. Stamminger 7.4 Unter der Lupe Anweisungen mit Label: Blockanfänge können mit Namen versehen werden. Namen heißen „Label“ outer: outer: for for (int (int row row == 0; 0; row row << numRows; numRows; row++) row++) {{ for for (int (int col col == 0; 0; col col << numCols; numCols; col++) col++) {{ ... ... break break outer;//beendet outer;//beendet äußere äußere for-Schleife for-Schleife }} }} for for (int (int i=0; i=0; ii << myArray.length; myArray.length; i++) i++) {{ if if (myArray[i] (myArray[i] == == null) null) {{ continue; continue; //überspringt //überspringt Rest Rest der der Schleife Schleife //startet //startet nächste nächste Iteration Iteration }} myArray[i].myMethod() myArray[i].myMethod() }} break verlässt die per Label genannte Schleife, continue startet eine neue Iteration dieser Schleife. Ohne Label ist die jeweils direkt umgebende Schleife betroffen. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-48 M. Stamminger 7.4 Unter der Lupe Statischer Initialisierer Zusätzlich zur Initialisierung statischer Variablen kann man einen statischen Initialisierer programmieren. Der enthaltene Code wird ausgeführt, sobald die Klasse in die JVM geladen wird. Statische Initialisierer und Initialisierungs-Code für statische Variablen werden in textueller Ordnung ausgeführt. class class Test Test {{ static static int int MAGIC; MAGIC; static static {{ MAGIC MAGIC == 4711; 4711; }} }} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-49 M. Stamminger 7.4 Unter der Lupe Initialisierungsreihenfolge (1) Auch wenn alle Instanzvariablen sichtbar sind (also nicht erst in späteren Blöcken deklariert werden), kann ihre Verwendung dennoch unzulässig sein class class Test Test {{ int int ii == j; j; int int jj == 1; 1; }} unzulässiger Vorwärtsverweis Vorwärtsreferenzen sind innerhalb von Variableninitialisierern von Instanzoder Klassenvariablen und innerhalb von statischen Initialisierern unzulässig. class class Test Test {{ Test() Test() {{ kk == 2; 2; }} int int jj == 1; 1; int int ii == j; j; int int k; k; }} OK, da Vorwärtsverweis nicht innerhalb der Initialisierer Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-50 M. Stamminger 7.4 Unter der Lupe Initialisierungsreihenfolge (2) Folge der Abarbeitung in textueller Reihenfolge class class Test Test {{ static static int int peek() peek() {{ return return j; j; }} static static int int ii == peek(); peek(); static int j = 1; static int j = 1; public public static static void void main main (String[] (String[] args) args) {{ System.out.println(i+", System.out.println(i+", "+j); "+j); }} }} OK Ausgegeben wird 0,1, weil zum Zeitpunkt der Initialisierung von i auf das dann noch mit seinem default-Wert initialisierte j zugegriffen wird. Erst später wird j durch seinen Initialisierer auf 1 gesetzt. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-51 M. Stamminger 7.4 Unter der Lupe Initialisierungsreihenfolge (3) Lokale Variablen müssen definitiv vor ihrer lesenden Benutzung mit einem Wert beschrieben werden. int int k; k; if if (v (v >> 00 && && (k (k == System.in.read()) System.in.read()) >= >= 0) 0) {{ System.out.println(k); System.out.println(k); }} OK, weil auf jedem Pfad durch den Code k sicher initialisiert wird. Die Bedingung kann nur zu true ausgewertet werden, wenn auch der zweite Teil ausgewertet wird. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-52 M. Stamminger 7.4 Unter der Lupe Initialisierungsreihenfolge (4) Der Übersetzer betrachtet den Code allerdings nur strukturell und berücksichtigt außer Wahrheitswerten keine Wert. int int k; k; int int nn == 5; 5; if if (n (n >> 2) 2) {{ kk == 3; 3; }} System.out.println(k); System.out.println(k); int int k; k; if if (flag) (flag) {{ kk == 3; 3; }} else else {{ kk == 44 }} System.out.println(k); System.out.println(k); Weil n zur Laufzeit den Wert 5 hat, wird k bei jeder Programmausführung initialisiert sein. Der Übersetzer berücksichtigt aber den Wert von n nicht und "sieht", dass k im else-Fall nicht initialisiert werden könnte. OK Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-53 M. Stamminger 7.5 Was geht hier schief? 1. Beispiel class class Exp Exp {{ public public static static void void main(String[] main(String[] args) args) {{ int int ii == 10; 10; int int jj == 12; 12; if if ((i ((i << j) j) || || (i (i == 3)) 3)) {{ System.out.println("Hello"); System.out.println("Hello"); }} }} }} i=3 ist Zuweisung mit Ergebnistyp int. Kann nicht mit || verknüpft werden. Übersetzer meldet den Fehler. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-54 M. Stamminger 7.5 Was geht hier schief? 2. Beispiel class class Exp Exp {{ public public static static void void main(String[] main(String[] args) args) {{ int int ii == 10; 10; int int jj == 12; 12; if if ((i ((i << j) j) || || (i (i == 3) 3) >> 5) 5) {{ }} System.out.println(i); System.out.println(i); }} }} Kein syntaktischer Fehler. Vermutlich ist der leere Rumpf der if-Anweisung nicht beabsichtigt. Hier wird in jedem Fall „10“ ausgegeben. Einrücken von println reicht nicht. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-55 M. Stamminger 7.5 Was geht hier schief? 3. Beispiel class class Test Test {{ public public static static void void main(String[] main(String[] args) args) {{ double double aa == 5.1; 5.1; double double bb == 20.32; 20.32; double double cc == 32.998; 32.998; System.out.println(findAvg(a,b,c)); System.out.println(findAvg(a,b,c)); }} main ist statische Methode. Aus statischem Kontext kann Objekt-Methode findAvg nicht aufgerufen werden. Übersetzer meldet den Fehler. double double findAvg(double findAvg(double a, a, double double b, b, double double c) c) {{ return return (( (( aa ++ cc ++ b) b) /3.0); /3.0); }} }} return-Wert nicht klammern (Codier-Regel) Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-56 M. Stamminger 7.5 Was geht hier schief? 4. Beispiel class class Hund Hund {{ public public static static void void main(String[] main(String[] args) args) {{ Pudel Pudel pp == new new Pudel(); Pudel(); Terrier Terrier tt == new new Terrier(); Terrier(); Hund Hund hh == Hund(); Hund(); hh == p; p; pp == h; h; pp == (Pudel) (Pudel) h; h; hh == new new Pudel(); Pudel(); pp == (Pudel) (Pudel) h; h; pp == t; t; pp == (Pudel) (Pudel) t; t; }} }} new fehlt. statischer Typfehler statisch ok Laufzeitfehler statischer Typfehler statischer Typfehler class class Pudel Pudel extends extends Hund Hund {{ ... ... }} class class Terrier Terrier extends extends Hund Hund {{ ... ... }} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-57 M. Stamminger 7.5 Was geht hier schief? 5. Beispiel found könnte uninitialisierte lokale Variable sein. Nur Instanzvariablen und Klassenvariablen werden automatisch intitialisiert. Der Übersetzer meldet den Fehler. class class Test Test {{ public public static static void void main(String[] main(String[] args) args) {{ int int index; index; boolean boolean found; found; for for (index (index == 0; 0; index index << 10 10 && && !found; !found; index++) index++) {{ if if (index (index >> Math.PI) Math.PI) {{ System.out.println(index System.out.println(index ++ "ist "ist größer größer als als Pi"); Pi"); found found == true; true; }} }} }} }} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-58 M. Stamminger 7.5 Was geht hier schief? 6. Beispiel main-Methode hat void als Ergebnistyp Parametername fehlt. public public class class Sum Sum {{ public public static static void void int int main(String[]) main(String[]) {{ int int a[] a[] == {1, {1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10}; 10}; lokale Variablen mit gleichem Namen verboten int Reihungsgrenzen 0...length-1 int sum sum == 0; 0; int int i; i; for for (int (int ii == 1; 1; ii <= <= a.length; a.length; i+) i+) {{ ++ sum += a[i]; sum += a[i]; System.out.println("The System.out.println("The sum sum is: is: ", ", sum) sum) }} }} } fehlt Konkatenation von Zeichenketten mit + ; fehlt Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-59 M. Stamminger 7.5 Was geht hier schief? 7. Beispiel Klassennamen beginnen mit einem Großbuchstaben. class class ex ex {{ ... ... void void test(int test(int i, i, long long j) j) {{ ... ... }} void void test(long test(long i, i, int int j) j) {{ ... ... }} ... ... e.test(1, e.test(1, 1); 1); e.test(1L, e.test(1L, 1); 1); }} Beide test-Methoden haben bei Typwandlung den gleichen „Abstand“. Es kann daher nicht statisch entschieden werden, welche am spezifischsten ist. Daher Fehler. Die zweite test-Methode passt besser. Alles OK. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2005/06, Folie 0-60 M. Stamminger