Organisatorisches Regelung um die Weihnachtspause y Freitag 24.12. sind keine Übungen y Ab Montag, 10.1. wieder regulärer Übungs- und Vorlesungsbetrieb Algorithmik 1 Prof. Dr. Michael Philippsen / Prof. Dr. Herbert Stoyan Friedrich-Alexander-Universität Erlangen-Nürnberg Informatik 2/8 Programmiersysteme / Künstliche Intelligenz Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-2 M. Philippsen / H. Stoyan Kapitel 7 - Java-Details 7.1 Codier-Regeln für Java 7.1 7.2 7.3 7.4 7.5 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. Codier-Regeln für Java Vererbung am Beispiel Graphische Oberfläche Unter der Lupe Was geht schief? Æ Derartige Regeln heißen Codier-Regeln. In diesem Abschnitt besprechen wir übliche Codier-Regeln für Java. Bitte einhalten! Handy aus! Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-3 Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-4 7.1 Codier-Regeln für Java 7.1 Codier-Regeln für Java Mehr Motivation Codier-Regeln für Dateinamen 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. Quellcode-Dateien haben den Suffix .java ByteCode-Dateien haben den Suffix .class Friedrich-Alexander-Universität Erlangen-Nürnberg Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-5 M. Philippsen M. Philippsen Maximal eine öffentliche Klasse pro Quelldatei. Ist eine öffentliche Klasse namens X im Quellcode, dann muss die Quellcode-Datei X.java heißen. Algorithmik 1, WS 2004/05, Folie 7-6 M. Philippsen 7.1 Codier-Regeln für Java 7.1 Codier-Regeln für Java Codier-Regeln für Programmdateien Codier-Regeln für class und interface Deklarationen Mehr als 2.000 Zeilen sollte keine Programmdatei lang sein Leerzeilen zur optischen Trennung Generelle Struktur jeder Programmdatei 1. Anfangskommentar 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 /* * Klassenname * * Versionsangabe * * Datum * * Copyright-Angabe, Autoren */ 5. Instanzvariablen in der Reihenfolge public, protected, (package), private 6. Konstruktoren 7. Methoden nach Funktionalität gruppiert unabhängig von der Sichtbarkeit 2. package und import-Anweisung 3. class und interface Deklarationen Friedrich-Alexander-Universität Erlangen-Nürnberg Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-7 M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-8 7.1 Codier-Regeln für Java 7.1 Codier-Regeln für Java Programmzeilenformatierung (1) Programmzeilenformatierung (2) 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 zu tief eingerückt würde, dann einen 8er-Schritt gegenüber der vorherigen Zeile einrücken. M. Philippsen someMethod1(longExpression1, longExpression2, longExpression3, longExpression4); var = someMethod(longExpression1, someMethod2(longExpression2, longExpression3)); longName1 = longName2 * (longName3 + longName4 - longName5) + 4 * longName6; //obige Formatierung ist besser als: longName1 = longName2 * (longName3 + longName4 - longName5) + 4 * longName6; Leerzeichen zwischen Operator und Operanden Friedrich-Alexander-Universität Erlangen-Nürnberg Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-9 M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-10 7.1 Codier-Regeln für Java 7.1 Codier-Regeln für Java Programmzeilenformatierung (3) Programmzeilenformatierung (4) //übliche Formatierung: someMethod(int anArg, Object anotherArg, String yetAnotherArg, Object andStillAnother) { ... } //wenn zu tief private static Object Object ... } eingrückt werden würde synchronized veryLongMethodName(int anArg, anotherArg, String yetAnotherArg, andStillAnotherArg) { mit „normaler“ Einrückregel, würde es in Folgezeile hier weitergehen. Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-11 M. Philippsen Werden Bedingungen von if-Anweisungen zu lang, stets mindestens 8 Schritte einrücken //schlechte Formatierung: if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { doSomethingAboutIt(); } //Verwenden Drucker o. //Terminal falsche //Zeilenlänge, dann ist //Rumpf leicht zu //übersehen! //besser: if ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { doSomethingAboutIt(); } Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-12 M. Philippsen 7.1 Codier-Regeln für Java Programmzeilenformatierung (5) Formatierung des Fragezeichen-Operators: 7.1 Codier-Regeln für Java Bedingung wahr? dann erster Ausdruck : sonst zweiter Ausdruck. Kommentare In Java unterscheidet man zwischen Kommentaren zur Implementierung und Kommentaren zur Dokumentation. y Implementierungskommentare werden mit // oder /*…*/ geschrieben. Bedingung in Klammern à Beschreiben Implementierungsgedanken à Vor-/Nachbedingungen, Invarianten à Auskommentieren von Code, der nicht mehr gebraucht wird //je nach Geschmack: alpha = (aLongBooleanExpression) ? (int) beta : gamma++; alpha = (aLongBooleanExpression) ? (int) beta : gamma++; alpha = (aLongBooleanExpression) ? (int) beta : gamma++; Leerzeichen nach expliziter Typwandlung Nie Leerzeichen bei unären Operatoren Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-13 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 Standard-Bibliotheken 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 M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-14 M. Philippsen 7.1 Codier-Regeln für Java 7.1 Codier-Regeln für Java Dokumentationskommentar am Beispiel (1) Dokumentationskommentar am Beispiel (2) /** * Returns an Image object that can then be painted * on the screen. * <p> * The name argument is a specifier that … * * @param url an absolute URL giving the base location * name the location of the image, relative to url * @return the image at the specified URL * @see Image */ public Image getImage(URL url, String name) { try { return getImage(new URL(url, name)); } catch (MalformedURLException e) { return null; } } Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-15 getImage public Image getImage(URL url, String name) Returns an Image object that can then be painted on the screen. The argument is a specifier that … Parameters: url - an absolute URL giving the base location name - the location of the image, relative to url Returns: the image at the specified URL See Also: Image Mehr Informationen unter: http://java.sun.com/j2se/javadoc/ Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-16 7.1 Codier-Regeln für Java 7.1 Codier-Regeln für Java Deklarationen (1) Deklarationen (2) 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 ohne Leerzeichen class Sample extende Object { int ivar; int ivar2; Sample(int i, int j) { ivar = i; ivar = j; } 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 M. Philippsen int emptyMethod() {} ... } } in eigener Zeile, eingerückt wie class Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-17 Leerzeichen Leerzeile } in eigener Zeile, eingerückt wie Sample Leerzeile ausnahmesweise } in gleicher Zeile Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-18 M. Philippsen 7.1 Codier-Regeln für Java 7.1 Codier-Regeln für Java Anweisungen (1) Anweisungen (2) Nur eine Anweisung pro Zeile { steht am Ende der Zeile derjenigen Anweisung, die Block öffnet return: Rückgabewert if (condition) { statements; nicht in Klammern () } if-Anweisungen: if (condition) { Stets {} verwenden, auch statements; wenn nur eine Anweisung } else { statements; in einem Zweig ist. Schleifen: } if (condition) { statements; } else if (condition) { statements; } else { statements; } for (initialization; condition; update) { statements; } Leerzeichen //leere Schleife: for (initialization; condition; update); while (condition) { statements; } do { statements; } while (condition); Leerzeichen zwischen Schlüsselwort und ( Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-19 Nicht mehr als 3 Variablen gleichzeitig verändern. Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-20 7.1 Codier-Regeln für Java 7.1 Codier-Regeln für Java Anweisungen (3) Anweisungen (4) switch-Anweisung: switch (condition) { case ABC: statements; /* fällt durch */ case DEF: statements; break; case XYZ: statements; break; default: statements; break; } Kommentar, wenn wirklich „Durchrauschen“ in den nächsten Fall beabsichtigt ist. Dann keine Leerzeile. Leerzeile zwischen zwei Fällen. try-Anweisung: try { statements; } catch (ExceptionClass e) { statements; } finally { statements; } ggf. ohne finally. 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 2004/05, Folie 7-21 M. Philippsen Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-22 M. Philippsen 7.1 Codier-Regeln für Java 7.1 Codier-Regeln für Java Namensgebung (1) Namensgebung (2) 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. 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 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.i2.algo1 Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-23 Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-24 M. Philippsen 7.1 Codier-Regeln für Java 7.1 Codier-Regeln für Java Code-Klarheit (1) Code-Klarheit (2) 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 Konstante Werte sollten (fast) nie explizit als Literale im Code stehen. Stattdessen Konstante mit Namen deklarieren und den Namen im Code nutzen. Keine Kettenzuweisungen machen: a = b = c; 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. 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 Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-25 M. Philippsen 7.2 Vererbung am Beispiel Algorithmik 1, WS 2004/05, Folie 7-26 M. Philippsen 7.2 Vererbung am Beispiel Festkörper Festkörperbeispiel (1) Festkörperbeispiel (2) Quader Kugel Quader Zylinder mit abstrakter Klasse: public abstract class Festkoerper { public final static float PI = 3.1415926; public abstract double oberflaeche(); public abstract double volumen(); } Quader: oder mit Interface: public interface Festkoerper { public final static float PI = 3.1415926; public double oberflaeche(); public double volumen(); } Beides ist sinnvoll, weil die Klasse nur abstrakte Methoden und Konstanten deklariert. Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen 7.2 Vererbung am Beispiel Quader Zylinder Radius, Höhe 2·π·Radius· π·Radius²·Höhe (Radius + Höhe) Kugel 4·π·Radius² Radius 4/3·π·Radius3 public class Quader implements Festkoerper { private double laenge, breite, hoehe; public double oberflaeche() { return 2 * (laenge * breite + laenge * hoehe + breite * hoehe); } public double volumen() { return laenge * breite * hoehe; } ...} Algorithmik 1, WS 2004/05, Folie 7-28 M. Philippsen Festkörperbeispiel (4) Zustand Oberfläche Volumen Länge, Breite, Höhe Länge·Breite·Höhe Radius 2·(Länge·Breite + Länge·Höhe + Breite·Höhe) Quader 2·π·Radius· π·Radius²·Höhe (Radius + Höhe) 4·π·Radius² 4/3·π·Radius3 Zylinder: Zustand Oberfläche Volumen Länge, Breite, Höhe Länge·Breite·Höhe 2·(Länge·Breite + Länge·Höhe + Breite·Höhe) Zylinder Radius, Höhe 2·π·Radius· π·Radius²·Höhe (Radius + Höhe) Kugel 4·π·Radius² Radius 4/3·π·Radius3 Kugel: public class Zylinder implements Festkoerper { private double radius, hoehe; public double volumen() { return PI * radius * radius * hoehe; } public double oberflaeche() { return 2 * PI * radius * (radius + hoehe); } ...} Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-29 Länge·Breite·Höhe 2·(Länge·Breite + Länge·Höhe + Breite·Höhe) 7.2 Vererbung am Beispiel Zylinder Radius, Höhe Kugel Volumen Länge, Breite, Höhe Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-27 Festkörperbeispiel (3) Zustand Oberfläche public class Kugel implements Festkoerper { private double radius; public double volumen() { return 4.0/3.0 * PI * radius * radius * radius; } public double oberflaeche() { return 4 * PI * radius * radius; } ...} Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-30 M. Philippsen 7.2 Vererbung am Beispiel Festkörperbeispiel (5) Festkoerper f = new Kugel(); System.out.println(f.volumen()); f = new Zylinder(); System.out.println(f.volumen()); 7.2 Vererbung am Beispiel Variable vom Typ einer Schnittstelle (oder einer abstrakten Klasse). Jede Instanz muss die Methoden der Schnittstelle implementieren. Abhängig vom dynamischen Typ des Objekts (von welchem Typ ist f zur Laufzeit?) wird die zugehörige konkrete Implementierung aufgerufen. interface BaseColors { int RED = 1; int GREEN = 2; int BLUE = 4; } interface RainbowColors extends BaseColors { int YELLOW = 3; int ORANGE = 5; int INDIGO = 6; int VIOLET = 7; } bei statischen Methoden und Instanzvariablen gelten andere Regeln Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-31 Mehrfachvererbung eingeschränkt auch in Java interface PrintColors extends BaseColors { int YELLOW = 8; int CYAN = 16; int MAGENTA = 32; } interface LotsOfColors extends RainbowColors, PrintColors { int FUCHSIA = 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 M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-32 M. Philippsen 7.2 Vererbung am Beispiel 7.3 Graphische Oberfläche Festkörperbeispiel (6) 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 AWTBibliothek (z. B. GridBagLayout) zurückgreifen. public class Kugel implements Festkoerper, LotsOfColors { ... int color = RED; //alles ok Kugel(int color) { if ((color < MIN_COLOR) || (color > MAX_COLOR)) { this.color = YELLOW; //Fehler zur Übersetzungszeit } else { this.color = color; } } } 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 Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-34 7.3 Graphische Oberfläche 7.3 Graphische Oberfläche Interaktionskomponenten (2) M. Philippsen Interaktionskomponenten (1) Algorithmik 1, WS 2004/05, Folie 7-33 JButton Knopf, Schaltfläche JCheckBox Ankreuzfeld JFrame Rahmen mit Titelbalken etc. JLabel Beschriftung JList Auswahlliste JPanel M. Philippsen JRadioButton Umschaltknopf ButtonGroup Mehrere Knöpfe, von denen nur einer gedrückt ist JScrollbar Verschiebebalken JSlider Schieberegler JTextField JTextArea Editierbares einzeiliges bzw. mehrzeiliges Textfeld Behälter zum Gruppieren und Anordnen v. Komponenten Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-35 Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-36 M. Philippsen 7.3 Graphische Oberfläche 7.3 Graphische Oberfläche Gedanklicher Aufbau eines Fensters: Aufbau eines Fensters in der Datenstruktur: Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-37 Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen 7.3 Graphische Oberfläche Algorithmik 1, WS 2004/05, Folie 7-38 7.3 Graphische Benutzeroberfläche Das erste Swing-Programm (2) Das erste Swing-Programm (1) Funktionalität wird in Objekten gekapselt Hier: beim Schließen des Fensters soll sich das Programm beenden import java.awt.*; import java.awt.event.*; import javax.swing.*; class MyCloser extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } public class RahmenMitKnopf { public static void main (String args[]) { JFrame r = new JFrame("RahmenMitKnopf"); Separate Klassendefinition für jedes mögliche Ereignis ist lästig. "Anonyme innere Klassen" helfen, s.u. 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 k = new JButton("Knoepfle"); k.SetToolTipText("tut nichts"); //Hinweistext r.getContentPane().add(k); Friedrich-Alexander-Universität Erlangen-Nürnberg ... JFrame r = new JFrame("RahmenMitKnopf"); r.addWindowListener(new MyCloser()); ... Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Wenn der Rahmen das Ereignis windowClosing sieht, dann wird die entspr. Methode des Objekts myCloser aufgerufen. Algorithmik 1, WS 2004/05, Folie 7-40 M. Philippsen 7.3 Graphische Oberfläche 7.3 Graphische Oberfläche Das erste Swing-Programm (3) Algorithmik 1, WS 2004/05, Folie 7-39 M. Philippsen 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()… import java.awt.*; import java.awt.event.*; import javax.swing.*; public class RahmenMitKnopf { public static void main (String args[]) { JFrame r = new JFrame("RahmenMitKnopf"); r.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); //Anonyme Innere Klasse! JButton k = new JButton("Knoepfle"); k.setToolTipText("tut nichts"); //Hinweistext r.getContentPane().add(k); r.pack(); r.setVisible(true); } } Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-41 Weitere Platzierer: y y y y Gitteranordnung (2D-Raster): Einfassungsanordnung: Schachtelanordnung: Variable Rasteranordnung: GridLayout BorderLayout BoxLayout GridBagLayout Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-42 M. Philippsen 7.3 Graphische Oberfläche 7.3 Graphische Oberfläche Gitteranordnung, GridLayout (1) Gitteranordnung, GridLayout (2) Einer der Konstruktoren: GridLayout(int zeilen, int spalten) Dieser legt ein Gitter mit der angegebenen Zeilen-/Spaltenzahl an. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Gitteranordnung{ public static void main(String[] args) { JFrame r = new JFrame("Gitter - Anordnung"); JPanel p = new JPanel(new GridLayout(2,3)); p.add(new JButton("Knopf1")); p.add(new JButton("Knopf2")); p.add(new JButton("3")); p.add(new JButton("Knopf mit langem Text")); p.add(new JButton("Knopf5")); r.getContentPane().add(p); r.pack(); r.setVisible(true); } } Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-43 Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-44 7.3 Graphische Oberfläche 7.3 Graphische Oberfläche Einfassungsanordnung, BorderLayout (1) Einfassungsanordnung, BorderLayout (2) maximal 5 Komponenten werden angeordnet: in der Mitte und in jeder der vier Himmelsrichtungen. class Einfassung { public static void main( String[] args ) { JFrame f = new JFrame("Gitter - Anordnung"); JPanel p = new JPanel(new BorderLayout()); f.getContentPane().add(p); JButton b = new JButton("Norden"); p.add(b, BorderLayout.NORTH); b = new JButton("Sueden"); p.add(b, BorderLayout.SOUTH); b = new JButton("Westen"); p.add(b, BorderLayout.WEST); b = new JButton("Osten"); p.add(b, BorderLayout.EAST); b = new JButton("Mitte"); p.add(b, BorderLayout.CENTER); f.pack(); f.setVisible( true ); } } Friedrich-Alexander-Universität Erlangen-Nürnberg Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-45 M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-46 7.3 Graphische Oberfläche 7.3 Graphische Oberfläche Schachtelanordnung, BoxLayout Variable Rasteranordnung, GridBagLayout Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-47 M. Philippsen M. Philippsen Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-48 M. Philippsen 7.4 Unter der Lupe 7.4 Unter der Lupe Anweisungen mit Label: Statischer Initialisierer Blockanfänge können mit Namen versehen werden. Namen heißen „Label“ 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. outer: for (int row = 0; row < numRows; row++) { for (int col = 0; col < numCols; col++) { ... break outer;//beendet äußere for-Schleife } } for (int i=0; i < myArray.length; i++) { if (myArray[i] == null) { continue; //überspringt Rest der Schleife //startet nächste Iteration } 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 class Test { static int MAGIC; static { MAGIC = 4711; } } Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-49 M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-50 M. Philippsen 7.4 Unter der Lupe 7.4 Unter der Lupe Initialisierungsreihenfolge (1) Initialisierungsreihenfolge (2) Auch wenn alle Instanzvariablen sichtbar sind (also nicht erst in späteren Blöcken deklariert werden), kann ihre Verwendung dennoch unzulässig sein Folge der Abarbeitung in textueller Reihenfolge class Test { int i = j; int j = 1; } unzulässiger Vorwärtsverweis Vorwärtsreferenzen sind innerhalb von Variableninitialisierern von Instanzoder Klassenvariablen und innerhalb von statischen Initialisierern unzulässig. class Test { Test() { k = 2; } int j = 1; int i = j; int k; } class Test { static int peek() { return j; } static int i = peek(); static int j = 1; public static void main (String[] args) { System.out.println(i+", "+j); } } 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. OK, da Vorwärtsverweis nicht innerhalb der Initialisierer Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-51 OK Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-52 M. Philippsen 7.4 Unter der Lupe 7.4 Unter der Lupe Initialisierungsreihenfolge (3) Initialisierungsreihenfolge (4) Lokale Variablen müssen definitiv vor ihrer lesenden Benutzung mit einem Wert beschrieben werden. Der Übersetzer betrachtet den Code allerdings nur strukturell und berücksichtigt außer Wahrheitswerten keine Wert. int k; if (v > 0 && (k = System.in.read()) >= 0) { 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 2004/05, Folie 7-53 int k; int n = 5; if (n > 2) { k = 3; } 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. int k; if (flag) { k = 3; } else { k = 4 } System.out.println(k); OK Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-54 M. Philippsen 7.5 Was geht hier schief? 7.5 Was geht hier schief? 1. Beispiel 2. Beispiel class Exp { public static void main(String[] args) { int i = 10; int j = 12; if ((i < j) || (i = 3)) { System.out.println("Hello"); } } } i=3 ist Zuweisung mit Ergebnistyp int. Kann nicht mit || verknüpft werden. Übersetzer meldet den Fehler. class Exp { public static void main(String[] args) { int i = 10; int j = 12; if ((i < j) || (i = 3) > 5) { } 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 Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-55 M. Philippsen 7.5 Was geht hier schief? Algorithmik 1, WS 2004/05, Folie 7-56 M. Philippsen 7.5 Was geht hier schief? 3. Beispiel class Test { public static void main(String[] args) { double a = 5.1; double b = 20.32; double c = 32.998; 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 findAvg(double a, double b, double c) { return (( a + c + b) /3.0); } } return-Wert nicht klammern (Codier-Regel) class Hund { public static void main(String[] args) { Pudel p = new Pudel(); Terrier t = new Terrier(); Hund h = Hund(); h = p; p = h; p = (Pudel) h; h = new Pudel(); p = (Pudel) h; p = t; p = (Pudel) t; } } statischer Typfehler statisch ok Laufzeitfehler statischer Typfehler statischer Typfehler Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-58 M. Philippsen 7.5 Was geht hier schief? 7.5 Was geht hier schief? 5. Beispiel 6. Beispiel found könnte uninitialisierte lokale Variable sein. Nur Instanzvariablen und Klassenvariablen werden automatisch intitialisiert. Der Übersetzer meldet den Fehler. class Test { public static void main(String[] args) { int index; boolean found; for (index = 0; index < 10 && !found; index++) { if (index > Math.PI) { System.out.println(index + "ist größer als Pi"); found = true; } } } } Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-59 new fehlt. class Pudel extends Hund { ... } class Terrier extends Hund { ... } Friedrich-Alexander-Universität Erlangen-Nürnberg Algorithmik 1, WS 2004/05, Folie 7-57 4. Beispiel main-Methode hat void als Ergebnistyp Parametername fehlt. public class Sum { public static void int main(String[]) { int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; lokale Variablen mit gleichem Namen verboten int sum = 0; Reihungsgrenzen 0...length-1 int i; for (int i = 1; i <= a.length; i+) { ++ sum += a[i]; System.out.println("The sum is: ", sum) } } } fehlt Konkatenation von Zeichenketten mit + ; fehlt Friedrich-Alexander-Universität Erlangen-Nürnberg M. Philippsen Algorithmik 1, WS 2004/05, Folie 7-60 M. Philippsen 7.5 Was geht hier schief? 7. Beispiel Klassennamen beginnen mit einem Großbuchstaben. class ex { ... void test(int i, long j) { ... } void test(long i, int j) { ... } ... e.test(1, 1); e.test(1L, 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 2004/05, Folie 7-61 M. Philippsen