Anwendungsorientierte Programmierung I Heinrich Krämer Hochschule für Technik, Wirtschaft und Kultur Leipzig (FH) Fachbereich Informatik, Mathematik und Naturwissenschaften Folie 2 1 Einleitung Literatur http://docs.oracle.com/javase/specs/ The Java™ Language Specification Hier findet sich die jeweils aktuelle Dokumentation Christian Ullenboom Java ist auch eine Insel Galileo Computing Anwendungsorientierte Programmierung Folie 3 1. Einleitung Schritte bei der Programmierung – Entwicklung eines Algorithmus Ein Algorithmus ist eine aus endlich vielen Schritten bestehenden eindeutige Handlungsvorschrift zur Lösung eines Problems oder einer Klasse von Problemen Diese Entwicklung erfolgt mehr oder weniger unabhängig von der Programmiersprache – Codierung des Algorithmus Hier wird der vorher entwickelte Algorithmus in einer bestimmten Programmiersprache (hier Java) notiert. Anwendungsorientierte Programmierung Folie 4 1 Einleitung Entwicklung eines Algorithmus Aufstellen einer Spezifikation • Eingabe mit genauer Angabe der zulässigen Wertebereiche • Ausgabe • funktionaler Zusammenhang Bewährt hat sich bei der Entwicklung die Top-DownMethode • Zerlegung in Teilprobleme bzw. Teilmodule (mit eigener Spezifikation) Wichtig! Es wird nur angegeben was ein Teilmodul leistet und nicht wie. • Prüfung ob das Zusammenspiel der Teilmodule das Problem löst. • Anwenden der Methode auf die Teilprobleme bis sich diese elementar lösen lassen. • Nachteil: Es kann vorkommen, dass eine Designentscheidung in unteren Schichten nicht lösbar ist. Anwendungsorientierte Programmierung Thomas Watson Sr. Folie 5 1 Einleitung Beispiel: Sieb des Eratosthenes Eingabe: Ganzzahliger Bereich der natürliche Zahlen [1..n] Ausgabe: alle Primzahlen in diesem Bereich funktionaler Zusammenhang: eine Primzahl ist nur durch 1 und sich selbst teilbar und ungleich 1 Algorithmus Datenstruktur: Tabelle mit allen Zahlen 2..n Idee: Streichen aller Zahlen die Vielfache einer Primzahl sind. Beobachtung: Es muss nur der Bereich 2.. n auf Vielfache untersucht werden 1. Teilproblem: Streichen der Vielfachen aller Primzahlen im Bereich 2.. n 2. Teilproblem: Ausgabe aller nicht gestrichenen Zahlen Anwendungsorientierte Programmierung Folie 6 1. Einleitung 1. Teilproblem: für die Zahlen in der Tabelle von 2 bis Wurzel(n) falls Zahl nicht gestrichen (Zahl ist Primzahl) gebe die Zahl aus Streiche alle Vielfache (Teilproblem) 2. Teilproblem: Für die Zahlen von Wurzel(n) +1 bis n falls Zahl nicht gestrichen gebe Zahl als Primzahl aus 1.1. Streichen aller Vielfachen pz ist Primzahl Für die Zahlen k := pz2 bis k > n Streiche k k := k + pz Anwendungsorientierte Programmierung Folie 7 1 Einleitung Programmierparadigmen Prozedurale (oder imperative) Programmierung Der Algorithmus wird als Abfolge von Anweisungen aufgefasst, welche jeweils Zustandsübergänge auf den Daten bewirken. Die Befehlsausführung wird durch Kontrollstrukturen gesteuert. Bestimmte Teilfunktionen werden zu Unterprogrammen zusammengefasst. Typische Programmiersprachen: Fortran, C, Pascal Objektorientierte Programmierung Hier werden die Daten in Klassen gekapselt. Auf den Daten werden bestimmte zu den Klassen gehörende Funktionen (Methoden) ausgeführt. Durch Polymorphie können verschiedene Kontrollstrukturen ersetzt werden. Typische Programmiersprachen: C++, Java, Delphi Anwendungsorientierte Programmierung Folie 8 2 Programmierspachen Programmiersprachen sind formale Sprachen mit fest vorgegebenen Syntax und dazugehörender Semantik. In der Syntax ist genau festgelegt wie Programme und bestimmte Konstrukte aufzuschreiben sind. Die Syntax wird in einer (kontextfreien) Grammatik festgelegt. Die Semantik legt die Bedeutung eines bestimmten Konstrukts fest. Die Syntax und Semantik für Java ist in The Java™ Language Specification festgelegt. Weiter gibt es meist Konventionen, die allgemein akzeptiert sind. Im Sinne eines guten Programmierstiel sollten diese Konventionen eingehalten werden. Anwendungsorientierte Programmierung Folie 9 2.1 Die Grammatik Die Grammatik einer Programmiersprache wird durch Produktionen angegeben. Eine Produktion besteht aus einem linken und einem rechten Teil, die durch einen Doppelpunkt getrennt sind. Auf der linken Seite steht ein Nichtterminal. Nichtterminale werden hier kursiv geschrieben. Auf der rechten Seite können Terminale oder Nichtterminale stehen. Terminale werden in Courier gesetzt. Ein Konstrukt ist syntaktisch korrekt, wenn alle Nichtterminale durch Terminale ersetzt sind. Beispiel: LocalVariableDeclarationStatement: Type VariableDeclarators ; Type: int VariableDeclarators: Identifier int zahl; Anwendungsorientierte Programmierung Folie 10 2.1 Die Grammatik Metazeichen x | y Auswahl: es kann entweder x oder y verwendet werden [ x ] das x ist optional. { x } das x kann beliebig oft oder keinmal auftreten Bezeichner (eng. Identifier) Für Variablen, und alle anderen später eingeführten Konstrukte wie Funktionen, selbst deklarierte Datentypen, Methoden, Klassen und Schnittstellen müssen eindeutige Namen, so genannte Bezeichner, vergeben werden. Ein Bezeichner muss immer mit einem Java-Buchstaben beginnen. Danach können beliebig Buchstaben und Ziffern folgen. Hierbei wäre es zulässig, beliebige Buchstaben aus dem Unicode-Alphabet zu verwenden. Nach üblicher Konvention sollten jedoch nur Buchstaben aus den Bereichen A..Z, a..z und die Ziffern 0..9 verwendet werden. Anwendungsorientierte Programmierung Folie 11 2.1 Grammatik Beispiele für Bezeichner eineVariable gültiger Bezeichner Noch_ne_Variable gültiger Bezeichner, verletzt aber Konvention __Win gültiger Bezeichner, kann allerdings zu Problemen führen $$system gültiger Bezeichner, kann allerdings zu Problemen führen Ungültige Bezeichner 1Fehler beginnt mit Ziffer Hoppla! keine Sonderzeichen auch falsch keine Leerzeichen Ein Bezeichner darf keines der nachfolgenden Schlüsselworte sein abstract assert boolean break byte case catch char class const continue default do double else extends false final finally float for goto if implements import instanceof int interface long native new null package private protected public return short static strictfp super switch synchronized this throw throws transient true try void volatile while Anwendungsorientierte Programmierung Folie 12 2.1 Grammatik Bisher wollen wir folgenden Rahmen verwenden JavaProgramm : package Bezeichner; {ImportDeklaration;} public class Bezeichner { public static void main() { {BlockAnweisung} } } Konvention: Bezeichner für Pakete (package) beginnen mit einem Kleinbuchstaben, Bezeichner für Klassen (class) beginnen mit einem Großbuchstaben Anwendungsorientierte Programmierung Folie 13 2.2 Primitive Datentypen Typ Wertebereich Größe Format Ganzzahlen (Numerisch) byte -128..+127 8 Bit Zweierkomplement short -32.768..+32.767 16 Bit Zweierkomplement int -2.147.483.648..+ 2.147.483.647 32 Bit Zweierkomplement long -263..+263-1 64 Bit Zweierkomplement 32 Bit IEEE 754 64 Bit IEEE 754 Gleitkommazahlen (Numerisch) float 1,40239846E-45..3,40282347E+38 double Weitere Datentypen boolean true oder false nicht def. char Unicode (Numerisch) 16 Bit Anwendungsorientierte Programmierung 16-Bit-Unicode Folie 14 2.2 Primitive Datentypen Literale dienen der Darstellung von konstanten Werten im Programm. Numerische Literale int–Literale 1234 (Dezimal) 0B10 oder 0b10 (Dual 210) 01234 (Oktal 66810 ) 0xFFFF_FFFF (Hexadezimal -110) long-Literale (es muss immer ein l angehängt werden) 1234L (Dezimal) 0b11L (Dual 310) 01234L (Oktal 66810 ) 0xFFFF_FFFFL (Hexadezimal 429496729510) float-Literale (es muss immer ein f angehängt werden) 1.0f 2F 1e-1f 4.0E+5f 3.1416E1f double-Literale 1.0 2D 1e-1d 4.0E+5 3.1416E1 Anwendungsorientierte Programmierung Folie 15 2.2 Primitive Datentypen char-Literale 'a' '\0041' (A) '\\' (\) '\'' ( ' ) '\"' ( " ) '\u4EBA' (人)* Einige Escape-Sequenzen '\b' Rückschritt (backspace) '\n' Zeilenumbruch (newline) '\f' Seitenumbruch (formfeed) '\r' Wagenrücklauf (return) * Eventuell muss in Eclipse ProjectProperties die Codierung auf UTF-8 umgestellt werden Anwendungsorientierte Programmierung Folie 16 Wrapper-Datentypen In manchen Fällen wird statt eines primitiven Datentypen eine Klasse (später) erwartet. Für diese Fälle gibt es zu die sog. Wrapper-Datentypen. Für diese Wrapper-Daten sind auch verschiedene Konvertierungen vorgesehen. Wrapper-Datentyp primitiver Datentyp Byte byte Short short Integer int Long long Float float Double double Boolean boolean Character char Anwendungsorientierte Programmierung Beispiel double x = Double.valueOf("3.1415"); Folie 17 Der Datentyp String String ist eigentlich kein primitiver Datentyp sondern ein Klasse. Diese dient zur Behandlung von Zeichenketten. An dieser Stelle sollen nur einige Besonderheiten behandelt werden Zeichenketten werden in Doppelhochkomma ( " ) eingeschlossen. Bsp.: "Ich bin eine Zeichenkette" Beachte: "C" 'C' Soll in der Zeichenkette ein " vorkommen, so muss hier eine Escape-Sequenz verwendet werden. Auch andere Escape-Sequenzen können nützlich sein. "Ich sagte:\n\t\"Kann ich was spenden?\"" ergibt die Ausschrift: Ich sagte: "Kann ich was spenden?" Strings können über + verkettet werden. Bsp. "\"Ich meinte" + "…\"" + '\n' + "\"Ich auch.\"" Ein Vergleich kann nur über die Methode equals(s) erfolgen. Bsp.: String abc = "Hallo"; abc.equals("Hallo") // liefert true abc == "Hallo" // liefert false Anwendungsorientierte Programmierung Folie 18 2.3 Operatoren Arithmetische Operatoren Unitäre Operatoren Typ Beschreibung Rang + Numerisch Vorzeichen 1 - Numerisch Vorzeichen 1 ++ Numerisch Inkrement (+1) 1 -- Numerisch Dekrement (-1) 1 Binäre Operatoren Anwendungsorientierte Programmierung Typ Beschreibung Rang + Numerisch Addition 3 - Numerisch Subtraktion 3 * Numerisch Multiplikation 2 / Numerisch Division 2 % Numerisch Modulo (Rest) 2 Folie 19 2.3 Operatoren Vergleichsoperatoren Typ Beschreibung Rang < Numerisch, char kleiner 5 > Numerisch, char größer 5 <= Numerisch, char kleiner oder gleich 5 >= Numerisch, char größer oder gleich 5 == Numerisch, char ungleich 6 != Numerisch, char gleich 6 logische Operatoren (Datentyp boolean) ! boolean Negation 1 && boolean UND (Kurzauswertung) 10 || boolean ODER (Kurzauswertung) 11 ^ boolean Antivalenz 8 & boolean UND 7 | boolean ODER 9 Anwendungsorientierte Programmierung Folie 20 2.3 Operatoren Bitweise Operatoren Typ Beschreibung Rang ~ Numerisch bitweises Komplement 1 & Numerisch bitweises UND 7 | Numerisch bitweises ODER 9 ^ Numerisch bitweise Antivalenz 8 << Numerisch Schieben links 4 >> Numerisch log. Schieben rechts 4 >>> Numerisch arith. Schieben rechts 4 1 weitere Operatoren (typ) alle Typumwandlung new alle später instanceof alle später 5 Auswahl 12 exp ? exp : exp Anwendungsorientierte Programmierung Folie 21 2.3 Operatoren Zuweisungsoperator (für Typ gilt immer lhs == rhs) Beschreibung Rang = Zuweisung 13 += Diese Art der Zuweisung ist eine Kurzform für die Zuweisung lhs = lhs op operand 14 -= *= /= %= <<= Beispiel x = x * 10.0 ist identisch zu x *= 10.0 >>= >>>= &= |= ^= Anwendungsorientierte Programmierung Folie 22 2.4 Ausdrücke Die Definition der Ausdrücke soll hier informell erfolgen. Durch die Operatoren können Ausdrücke gebildet werden. Operatoren mit kleinerem Rang werden vor Operatoren mit höherem Rang ausgewertet. Haben Operatoren gleichen Rang so werden diese von links nach rechts ausgewertet. Einen Ausnahme bildet die Zuweisung, die von rechts nach links ausgewertet wird. double x = 1.0 / 2.0 + 3.0 * 4.0 berechnet sich zu double x = ((1.0 / 2.0) + (3.0 * 4.0)) Bei den logischen Operatoren && und || erfolgt eine Kurzauswertung. Kann das Ergebnis bereits durch Auswertung des linken Operanden bestimmt werden, so wird der rechte nicht mehr bewertet. Post- und Preinkrement bzw. –dekrement --a Predekrement b++ Postinkrement Anwendungsorientierte Programmierung Folie 23 2.4 Ausdrücke Ausdrücke müssen immer einen festen Typ ergeben. Daher müssen sich die einzelnen Operanden implizit in den Zieltyp umwandeln lassen oder es muss eine explizite Typumwandlung (Type cast) erfolgen. Implizite Typkonversion byte short int X short int long float Anwendungsorientierte Programmierung long float double X X X X X X X X X (X) X (X) (X) X Folie 24 2.5 Anweisungen Vereinfachte Grammatik für Anweisungen BlockAnweisung: LokaleVariableDeklarationAnweisung | Anweisung LokaleVariableDeklarationAnweisung: LokaleVariableDeklaration; LokaleVariableDeklaration Typ VariablenDeklaratoren VariablenDeklaratoren: VariablenDeklarator {, VariablenDeklarator } VariablenDeklarator: Bezeichner [= Ausdruck] Beispiele füe Variablendeklarationen int eineZahl, meineZahl = 17, nochEineZahl = 0; double x = 0.0, sigma = 0.1E-3, ergebnis; Anwendungsorientierte Programmierung Folie 25 2.5 Anweisungen BlockAnweisung: //heute Block AusdrucksAnweisung IfAnweisung WhileAnweisung DoAnweisung Block: { {BlockAnweisung } } Blöcke dienen der Zusammenfassung von mehreren Anweisungen zu einer. Anwendungsorientierte Programmierung Folie 26 2.5 Anweisungen In der AusdrucksAnweisung sind (im Moment) nur Zuweisung; Preinkrementausdruck; Postinkrementausdruck; Predekrementausdruck; Postdekrementausdruck ; erlaubt. Solche Ausdrücke werden durch den Abschluss mit einem Semikolon zu einer Anweisung. Beispiele x = 3.1416; y = r = 2.0 * x; a++; --a; b = ++a * 10; Anwendungsorientierte Programmierung Folie 27 Sichtbarkeit und Lebensdauer package bezeichner; {ImportDeklaration;} public class Bezeichner { public static void main() { int n, k = 1; //Variablendeklaration { // Block double x = 2.0; int n = 5; //illegal x++; // Postinkrementanweisung System.out.println(x); // Ausgabe 3.0 n = x + k; // illegal } n = k + 3; System.out.println(n); // Ausgabe 4 System.out.println(x); // illegal } } Anwendungsorientierte Programmierung Folie 28 Konventionen Bezeichner für Klassen beginnen immer mit einem Großbuchstaben Bezeichner für Variablen und Funktionen (Methoden) beginnen mit einem Kleinbuchstaben Durch die Verwendung von Groß- Kleinbuchstaben kann der Bezeichner strukturiert werden. Bsp.: MyFirstClass // Klassenbezeichner thisIsAVariable //Variablenbezeicher meineErsteFunktion() // Funktionsbezeichner Variablen sollten immer am Anfang einer Funktion (Methode) deklariert werden. Die Deklaration von Variablen innerhalb eines Blocks ist auf Hilfsvariablen zu beschränken. Anwendungsorientierte Programmierung Folie 29 2.5 Anweisungen IfAnweisung : if (Ausdruck) Anweisung [else Anweisung] Die IfAnweisung dient zur Fallunterscheidung Beispiele: int i = 19, k = 3; if (k == 0) System.out.println("nix vorhanden"); if (k == 0) System.out.println("nix vorhanden"); else { System.out.println(k); i /= k; } Anwendungsorientierte Programmierung Folie 30 2.5 Anweisungen WhileAnweisung: (Schleife) while ( Ausdruck ) Anweisung Eine Schleife dient zur mehrfachen Ausführung einer Anweisung. Beispiele: int a = 10; while (a >= 0) a--; while (a >= 0) a--; System.out.println(a); //wahrscheinlich fehlerhaft Anwendungsorientierte Programmierung while (a >= 0){ a--; System.out.println(a); } // Block Folie 31 2.5 Anweisungen DoAnweisung: (Schleife) do Anweisung while ( Ausdruck ); Im Gegensatz zur While-Schleife wird die Anweisung immer mindestens einmal ausgeführt Beispiele: int n; do n = tastatur.nextInt(); while (n != 0); Anwendungsorientierte Programmierung do n = tastatur.nextInt(); System.out.println(n); while (n != 0); // Fehlerhaft Folie 32 2.5 Anweisungen ForAnweisung: for ([ForInit];[Ausdruck];[ForUpdate]) Anweisung Im optionalen ForInit Teil können mehrere Variablen, durch Komma getrennt, deklariert und initialisiert werden. Die Schleife wird solange ausgeführt, wie der Ausdruck true ergibt. ForUpdate ist ein Ausdruck, der bei nach jedem Schleifendurch ausgewertet wird. Die in den runden Klammern deklarierten Variablen sind nur innerhalb des Schleifenrumpfes sichtbar Beispiel: int sum = 0; for(int i = 1; i <= 10; i++) sum += i; Anwendungsorientierte Programmierung Folie 33 2.5 Anweisungen Verwendung der Schleifen forAnweisung: Sollte immer verwendet werden, wenn in der Schleife eine Variable um einen festen Wert inkrementiert oder dekrementiert wird. Vor allem sollte vermieden werden im Schleifenkopf komplexe Berechnungen durchzuführen. whileAnweisung: Dient zur Durchführung von aufwändigeren Berechnungen. Es ist hier darauf zu achten, dass alle Variablen vor der Schleife einen Wert erhalten haben (initialisiert sind). Weiter ist zu überprüfen, ob die Berechnung zu einem Abbruch führt. doAnweisung: Sollte nur verwendet werden, falls es erforderlich ist (z. B. Eingabe). Vor allem ist darauf zu achten, dass der erste Schleifendurchlauf nicht zu illegalen Zuständen führt. Anwendungsorientierte Programmierung Folie 34 2.5 Anweisungen ContinueAnweisung: continue [Label]; Nachtrag: Vor jeder Anweisung kann ein Label stehen. continue ohne Label : Darf nur in Schleifen stehen. Bei erreichen der Anweisung wird die Ausführung des Programms am Beginn der innersten Schleife fortgesetzt. continue mit Label : Der Programmlauf wird an die Anweisung mit dem Label transferiert. BreakAnweisung: break [Label]; break ohne Label : Darf nur in Schleifen (oder SwitchAnweisung) stehen. Bei erreichen der Anweisung wird die Ausführung der innersten Schleife abgebrochen. break mit Label : Der Programmlauf wird an die Anweisung mit dem Label transferiert. Anwendungsorientierte Programmierung Folie 35 2.5 Anweisungen SwitchAnweisung: switch ( Ausdruck ) { { case CaseMarke : { Anweisung } } [ default: { Anweisung } ] } CaseMarke kann eine Konstante vom Typ char, byte, short, int, Character, Byte, Short, Integer, String oder ein Aufzählungtyp (später) sein. Der Datentyp muss mit dem Typ des Ausdrucks übereinstimmen. Anwendungsorientierte Programmierung Folie 36 2.5 Anweisungen Beispiel int auswahl; // hier erhält auswahl einen Wert switch (auswahl) { case 1 : case 2 : // Anweisungen für die Fälle 1 oder 2 break; case 3 : // Anweisungen für den Fall 3 break; default: // Anweisungen falls kein Fall zutrifft } Anwendungsorientierte Programmierung Folie 37 2.5 Anweisungen Regeln für switchAnweisungen 1. Die Anweisungsfolge für jeden Fall (case) oder Fälle muss durch eine breakAnweisung (break) abgeschlossen werden. 2. Grundsätzlich sollte jede caseAnweisung ein default enthalten. Hier handelt es sich meist um einen Entwurfsfehler, daher sollte immer eine Fehlermeldung ausgegeben werden. Anwendungsorientierte Programmierung Folie 38 3 Benutzerdefinierte Datentypen Felder dienen der Zusammenfassung gleichartiger Daten. Beispiel: Es sollen 10 Messwerte aufgenommen werden. Deklaration des Feldes double[] messwerte; (alternativ double messwerte[];) Bei der Deklaration haben Felder noch keinen Speicherplatz reserviert. Dieser muss erst durch int n = 10; messwerte = new double[n]; angelegt werden. Der Zugriff auf einzelne Elemente erfolgt durch Angabe eines Indexes messwerte[0] greift auf das 0te Element zu. Durch messwerte.length kann die Anzahl der Elemente ermittelt werden. Die Indices müssen im Bereich 0..messwerte.length-1 liegen. Anwendungsorientierte Programmierung Folie 39 3.1 Felder (Arrays) Beispiel: Einlesen der Messwerte und Ausdrucken int n = 10; double[] messwerte = new double[n]; for(int i = 0; i < n; i++) { System.out.print("Messwert > "); messwerte[i] = tastatur.nextDouble(); } for(int i = 0; i < n; i++) { System.out.print(i+"ter Messwert = " + messwerte[i]); } Anwendungsorientierte Programmierung Folie 40 3.1 Felder Mehrdimensionale Felder Es ist möglich, Felder mit einer belieben Anzahl von Indices zu deklarieren double[][] matrix; Anlegen des Speichers matrix = new double[4][4]; deklariert ein zweidimensionales Feld. Der Zugriff auf ein einzelnes Element erfolgt durch: matrix[1][2] Anwendungsorientierte Programmierung Folie 41 3.1 Felder Felder können bei der auch mit einem Initialwert belegt werden String[] haustiere = {"Hund","Katze","Python","Springmaus"}; double[][] em = { { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 } }; Felder und die erweiterteforAnweisung: for (elemTyp variable : Feldvariable) Anweisung Diese Form der forAnweisung läuft automatisch über das ganze Feld und liefert in der Variablen das jeweils nächste Feldelement. Anwendungsorientierte Programmierung Folie 42 3.1 Felder Felder können bei der Deklaration auch mit einem Initialwert belegt werden String[] haustiere = {"Hund","Katze","Python","Springmaus"}; double[][] em = { { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 } }; Felder und die erweiterteforAnweisung: for (elemTyp variable : Feldvariable) Anweisung Diese Form der forAnweisung läuft automatisch über das ganze Feld und liefert in der Variablen das jeweils nächste Feldelement. Anwendungsorientierte Programmierung Folie 43 3.1 Felder Beispiel für die Verwendung der erweiterten for-Anweisung String[] haustiere = {"Hund","Katze","Python","Springmaus"}; for (String tier : haustiere) System.out.println(s); double[][] em = { { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 } }; for (double[] row : em) { for (double x : row) System.out.print(x); System.out.println(); } Anwendungsorientierte Programmierung Folie 44 3.2 Referenzen Referenzen Wird der Speicherplatz einer Variablen durch new erzeugt, handelt es sich um sogenannte Referenzen. In der eigentlichen Variablen wird nicht der Wert eines Objekts gespeichert, sondern nur ein Verweis (Adresse) auf den Speicherbereich. In anderen Programmiersprachen wird dies als Zeiger (pointer) bezeichnet. Diese existieren in Java nicht. Wurde für eine Referenz noch kein Speicherplatz mit new angelegt, handelt es sich um eine null-Referenz. Vor einem Zugriff, muss sichergestellt werden, dass keine null-Referenz vorliegt. Sonst erhält man einem Laufzeitfehler Felder sind immer Referenzen Anwendungsorientierte Programmierung Folie 45 3.3 Klassen Klassen An dieser Stelle soll nur eine vereinfachte Version für Klassen dargestellt werden. Im Kapitel objektorientierte Programmierung werden Klassen ausführlicher dargestellt. Deklaration (vereinfacht) [Modifizierer] class Klassennamen { { Klassenelemente } } Klassenelemente: Attributdeklaration Methodendeklaration Modifizierer (hier) public private Anwendungsorientierte Programmierung Folie 46 3.3 Klassen Attributdeklaration: [Modifizierer] Variablendeklaration Methodendeklaration: [Modifizierer] Rückgabetyp Methodenname (Parameter) { { Anweisungen } } Rückgabetyp: Typ void Anwendungsorientierte Programmierung Folie 47 3.3 Klassen // Klasse können überall benutzt werden public class Zylinder { // Daten sind von außen nicht sichtbar private double radius; private double hoehe; // Zugriff auf Daten nur über Methoden (setter, getter) public void setRadius(double r) { radius = r; } public double getRadius() { return radius; } public void setHoehe(double h) { hoehe = h; } public double getHoehe() { return hoehe; } } Bem: Wird eine Klasse als public deklariert, so muss durch package->new->class eine neue Datei erzeugt werden Anwendungsorientierte Programmierung Folie 48 3.3 Klassen Verwendung Deklaration Zylinder zylinder; Anlegen von Speicherplatz (Klassen sind immer Referenzen) zylinder = new Zylinder(); Setzen von Radius und Höhe zylinder.setRadius(2.0); zylinder.setHoehe(10.5); Lesen der Daten double r = zylinder.getRadius(); double h = zylinder.getHoehe(); Anwendungsorientierte Programmierung Folie 49 4 Unterprogramme Vorbemerkung: Java ist vom ganzen Konzept her eine objektorientierte Programmiersprache. Eine Verwendung von Java für prozedurale Programmierung ist nicht vorgesehen. Die hier vorgestellten Methoden sollten daher NICHT für echte Java-Programme verwendet werden. Es soll jedoch dieses Programmierparadigma mit Hilfe von Java vorgestellt werden. Verwendung von Unterprogrammen – Oftmals gibt es in einem Programm nahezu identische Programmteile. Diese können zu Unterprogrammen zusammengefasst werden und müssen daher nur einmal programmiert werden. Unterschiede werden durch Parameter realisiert. – Unterprogramme werden auch zur Strukturierung eingesetzt. Hierbei sollten die Unterprogramme den Entwurfsprozess widerspiegeln. Es gilt die Regel, dass ein fortlaufender Programmtext nicht länger als ein oder zwei Bildschirmseiten sein sollte. Anwendungsorientierte Programmierung Folie 50 4 Unterprogramme Deklaration eines Unterprogramms Alle Deklarationen erfolgen in der Klasse die das Hauptprogramm main enthält. static Rückgabetyp Unterprogrammname( Parameter ) { { Anweisungen } } Rückgabetyp: Typ void Parameter: [Typ Parametername {, Typ Parametername} ] Als Rückgabetyp sind auch Felder und Klassen zulässig Der Modifizierer static wird später behandelt und muss hier immer stehen. Anwendungsorientierte Programmierung Folie 51 4 Unterprogramme Die returnAnweisung return; //1 return Ausdruck; //2 1. Diese Art der returnAnweisung darf nur in Unterprogrammen mit dem Rückgabetyp void verwendet werden. Hierdurch kann ein vorzeitiger Rücksprung erreicht werden. In einem Unterprogramm können mehrere returnAnweisungen vorkommen. 2. Die returnAnweisung mit Ausdruck muss in Unterprogrammen mit Rückgabetyp ungleich void stehen. Es ist notwendig, dass auf jedem Ausführungspfad eine returnAnweisung erreicht wird. Durch den Wert des Ausdrucks wird der zurückgegebene Wert bestimmt. Anwendungsorientierte Programmierung Folie 52 4 Unterprogramme Beispiel static double max( double a, double b) { // a und b sind formale Parameter if ( a > b ) return a; else return b; } Aufruf double x = 10, y = 17, z; z = max(x, y - 10) // x und (y - 10) sind aktuelle Parameter Anwendungsorientierte Programmierung Folie 53 4 Unterprogramme Signatur Der Name und die Reihenfolge der Datentypen in der Parameterliste wird als Signatur bezeichnet Beispiele: static void up1(double x, int n, Zylinder z) { … } hat die Signatur up1(double, int, Zylinder) static int up2(double y, float a) { … } hat die Signatur up2(double, float) Die Namen der Parameter und der Rückgabetyp werden bei der Signatur nicht berücksichtigt Es ist unzulässig, in einer Klasse Unterprogramme (Methoden) mit gleicher Signatur zu deklarieren. z. B.: static void up2(double d, float b) { … } ist eine illegale Deklaration; aber static int up2(int d, float b) { … } ist legal. Anwendungsorientierte Programmierung Folie 54 4.1 Parameterübergabe Zunächst sollen primitive Datentypen betrachtet werden // Deklaration static double max(double a; double b) { return (a > b)? a : b; } Umgebung von max a b Aufruf von max double x = 18.1; double y = 5.9; Zunächst werden die Ausdrücke bewertet y * 10.0 = 59.0 und x / 10.0 = 1.81 Diese Werte werden dann in die Umgebung kopiert double z = max(y*10.0, x / 10.0); Die Berechnung erfolgt in der Umgebung, somit ist eine Änderung der aktuellen Parameter durch das Unterprogramm nicht möglich (Wertparameter, call by value) Anwendungsorientierte Programmierung a 59.0 b 1.81 Folie 55 4.1 Parameterübergabe Benutzerdefinierte Datentypen (Felder oder Klassen) Benutzerdefinierte Datentypen sind grundsätzlich Referenzen. Leider wird in Java der eigentliche Mechanismus verdeckt. radius Zylinder z = new Zylinder(); Referenzvariable z Adresse static void weird(Zylinder k) { k.setRadius(1.0) // Ändert den Eintrag Zylinder neu = new Zylinder(); k = neu; // keine Änderung an z (aber an k) } weird(z); //Aufruf Anwendungsorientierte Programmierung k Adresse von z hoehe Speicher für Zylinder Folie 56 4.2 Rekursive Unterprogramme Unterprogramme können auch andere Unterprogramme und auch sich selbst aufrufen. Das wird als rekursiver Aufruf bezeichnet. Beispiel: static void fakultaet(int n) { if (n < 0) return -1; // Fehler // Rekursionsbasis if ((n == 0) || (n == 1)) return 1; else // Rekursion return n * fakultaet(n-1) } Anwendungsorientierte Programmierung Folie 57 5 Verwendung vordefinierter Klassen Ableitung von Klassen Oberklasse (Basisklasse) Unterklasse (abgeleitete Klasse) Kutsche Anzahl Pferde erben: Sitzpläze Fahrrad Kraftfahrzeug Motorleistung void kraftfahrstrasse(Kraftfahrzeug f) { …} PKW ferrari = new PKW(); Fahrrad peugeot = new Fahrrad(); PKW kraftfahrstrasse(ferrari); // legal da Kraftfahrzeug hat Sitzplätze kraftfahrstrasse(peugeot); // kein Kraftfahrzeug Motorleistung Anwendungsorientierte Programmierung LKW Spezialisierung Fahrzeug Sitzplätze Folie 58 5.1 Die Klasse Exception package java.lang.Exception (Auszug) Ableitungsbaum Exception e IOException FileNotFoundException RuntimeException IllegalArgumentException NumberFormatException nützliche Methoden • e.getClass().getName() liefert die Ausnahme als String • e.getMessage() liefert Fehlermeldung • e.toString() liefert Name und Fehlermeldung • e.printStackTrace() Stapelabzug Anwendungsorientierte Programmierung Folie 59 5.1 Fehlerbehandlung TryCatchBlock try { { Anweisungen } } {catch ( ExceptionTyp Name){ { Anweisungen } }} [finally { { Anweisungen } }] Anwendungsorientierte Programmierung Folie 60 5.1 Fehlerbehandlung Beispiel try { // // // } catch if Anweisungen die eine allgemeine IOException, eine FilenotFoundException oder eine NumberFormatException auslösen (IOException e) { (e isinstanceof FileNotFoundExcception) { // Behandlung von dieser Ausnahme } else { // allgemeiner Eingabefehler } } catch (NumberFormatException e) { // Behandlung dieser Ausnahme } finally { // wird immer ausgeführrt } Anwendungsorientierte Programmierung Folie 61 5.1 Fehlerbehandlung Weiterleiten Will ein Unterprogramm Ausnahmen nicht selbst behandeln, so kann es diese an den Aufrufer weiterleiten public static void getFile(String filename) throws FileNotFoundException { // Anweisungen die eine FileNotFoundException auslösen // können } zeichnen.setText( Auslösen von Exceptions public static void setAge( int a) throws IllegalArgumentException { if (a <= 0) throw new IllegalArgumentException("Age must be > 0!"); age = a; } Anwendungsorientierte Programmierung Folie 62 5.1 Fehlerbehandlung Checked und Unchecked Exceptions – Checked Exceptions Diese Art der Exceptions müssen behandelt werden • Durch TryCatchBlock • Durch Weiterleiten mit throws Exception1, Exception2 … Beispiel: IOException – Unchecked Exceptions Diese können zum Aufrufer ohne Behandlung weitergeleited werden. Hierzu gehören: Error, RunTimeExceptions und alle Unterklassen Anwendungsorientierte Programmierung Folie 63 6 Dateien Die Klasse File Zur Benutzung dieser Klasse muss diese mit import java.io.* importiert werden Mit der Klasse file wird die Verbindung zwischen Dateien des Betriebssystems und programminternen Variablen hergestellt. Einige Methoden der Klasse File(String pathname) erzeugt ein File Objekt Die Konstanten File.separatorChar (Typ char) und File.sparator (Typ String) liefernden Betriebsystem spezifischen Pfadtrenner (z. B. '\' Windows, '/' Unix) boolean exists() gibt an, dass die Datei vorhanden ist boolean isDirectory() liefert true für ein Verzeichnis boolean isFile() liefert true für eine normale Datei Anwendungsorientierte Programmierung Folie 64 6 Dateien Schreiben in Dateien Dateien werden in Java als Datenströme (streams) gesehen. Daher muss zunächst ein OutputStream erzeugt werden. File f = new File("C:\javatexte\daten.txt"); OutputStream ostream = new FileOutputStream(f); // oder OutputStream ostream = new FileOutputStream(f, true); // erweitern der Datei Es kann eine FileNotFoundException ausgelöst werden Setzen eines Schreibers mit Zeichencodierung PrintStream writer = new PrintStream(ostream,"ISO8859_1"); Auf der Variablen writer sind nun die von System.out bekannten Methoden deklariert. Es kann eine UnsupportedEncodingException ausgelöst werden Anwendungsorientierte Programmierung Folie 65 6 Dateien Schreiboperationen (Bsp.) writer.print("Ein Text ohne Zeilenumbruch"); writer.println("Ein Text mit Zeilenumbruch"); writer.printf("Eine formatierte Zahl: %6.2f",2.0); Grundsätzlich werden Schreiboperationen gepuffert. Damit eine Ausgabe tatsächlich geschrieben wird, muss der Puffer geleert werden: writer.flush(); Weiter müssen alle geöffneten Dateien spätestens am Ende des Programms geschlossen werden: writer.close(); Anwendungsorientierte Programmierung Folie 66 6 Dateien Lesen aus Dateien Das Lesen erfolgt analog dem Schreiben File f = new File("C:\javatexte\daten.txt"); InputStream istream = new FileInputStream(f); Es kann eine FileNotFoundException ausgelöst werden Setzen eines Lesers mit Zeichencodierung Scanner reader = new Scanner(istream,"ISO8859_1"); Es kann eine UnsupportedEncodingException ausgelöst werden Es muss der Scanner importiert werden über: import java.util.Scanner; Anwendungsorientierte Programmierung Folie 67 6 Dateien Leseoperationen Der Scanner ist ein sehr leistungsfähiges Hilfsmittel. (Bitte nachlesen) Einige Beispiele reader.nextXXX(); // XXX = Byte, Int, Double usw. liest einen Wert ein Damit kein Lesefehler auftritt sollte immer zuerst mit if (reader.hasNextXXX()) { reader.nextXXX(); } geprüft werden ob ein solches Token überhaupt vorhanden ist Anwendungsorientierte Programmierung Folie 68 Objektorientierte Programmierung Anwendungsorientierte Programmierung Folie 69 7 Objektorientierte Programmierung Konzepte und Begriffe Ein Programm besteht aus mehreren Objekten. Diese können Aufträge erledigen, den Zustand ändern und berichten und mit anderen Objekten kommunizieren. Die konkrete Implementierung wird hierbei verborgen. Gleichartige Objekte werden in Java durch eine Klasse beschrieben. Ein konkretes Objekt wird als Instanz der Klasse bezeichnet. Daten werden durch die Attribute der Klassen gehalten. Das Verhalten wird durch die Methoden der Klasse bestimmt. Eine Änderung von Attributen darf nur durch Methoden erfolgen. Aus Klassen lassen sich spezialisiertere Klassen ableiten. Diese erben alle oder Teile der Eigenschaften der Basisklasse. Durch Polymorphie können sich Methoden je nach Bindung unterschiedlich verhalten. Anwendungsorientierte Programmierung Folie 70 7.1 Schreiben eigener Klassen Organisation von Java-Programmen package a // Paket package b // Unterpaket … public class C { … } //Klassen (compilation units) class D { … } a.b vollständig qualifizierter Name des Unterpakets b a.b.C vollständig qualifizierter Name der Klasse C Der vollständig qualifizierte Name muss eindeutig sein. Sichtbarkeitsregeln: Alle compilation units haben Zugriff auf die im Paket deklarierten Typen und auf als public deklarierte Typen aus java.lang Auf public deklarierte Typen kann von außen zugegriffen werden. Allerdings muss das Paket importiert werden. Anwendungsorientierte Programmierung Folie 71 7.1 Schreiben eigener Klassen Klassen [Modifizierer] class Klassennamen [extends Klassenname]{ { Klassenelemente } } Klassenelemente: Attributdeklaration Methodendeklaration Unterklassen Modifizierer public protected private abstract static final strictfp Anwendungsorientierte Programmierung Folie 72 7.1 Schreiben eigener Klassen Für Klassen auf der obersten Ebene sind die zulässigen Modifizierer nur: public abstract final (einzelne können/müssen entfallen) Bedeutung der Modifizierer public: Die Klasse ist an jeder Stelle eines Programms sichtbar, falls das Paket sichtbar ist. Fehlt der Modifizierer public, so ist die Klasse nur innerhalb des Pakets sichtbar. Nützlich für "lokale" Klassen. abstract, final später Klassen können auch innere Klassen besitzen. Innere Klassen können auch static oder private deklariert werden. Anwendungsorientierte Programmierung Folie 73 7.1 Schreiben eigener Klassen Modifizierer bei Attributen und Methoden public: analog Klasse private: Attribute sollten, Methoden können privat deklariert werden. Hierdurch sind diese nicht mehr von außen zugreifbar. Bei Attributen erfolgt der Zugriff über Zugriffsfunktionen (setter, getter). Private Methoden dienen der Strukturierung im Sinne von Unterprogrammen, wobei diese nur für interne Berechnungen benötigt werden static: Methoden und Attribute existieren außerhalb von Objektinstanzen. final: Attribute können nur einmal zugewiesen werden. Es handelt sich also praktisch um Konstante. Diese werden meist in Großbuchstaben geschrieben und dürfen auch als public deklariert werden. Der Modifizierer final für Methoden wird später erklärt. Anwendungsorientierte Programmierung Folie 74 7.1 Schreiben eigener Klassen Beispiel Bsp obj = obj.read() // zulässig public class Bsp { obj.nr = 10; // unzulässig private int index; obj.setNr(10); // zulässig private int nr; public void setNr(int nrPar) { obj.index = 1; //unzulässig nr = nrPar; // index ist nicht zugreifbar } obj.print(); // ok public int getNr() { Bsp.print(); // unzulässig return nr; } int i = obj.foo() // unzuässig, da public void print() { …} // private private int foo() {…} int i = obj.nr; // s.o. public Bsp read() {…} } Anwendungsorientierte Programmierung Folie 75 7.1 Schreiben eigener Klassen nicht statische und statische Elemente Im allgemeinen werden die Attribute und Methoden einer Klasse nicht statisch deklariert. Damit sind diese an ein konkretes Objekt (Instanz) der Klasse gebunden. Statische Attribute und Methoden existieren außerhalb von konkreten Objekten und sind an die Klasse gebunden. Statische Elemente sollten nur in bestimmten Spezialfällen verwendet werden. public class Bsp { private static int anzahl = 0; private int nr = ++anzahl; public void printNr() { { … } { System.out.println(nr); } public void printAnzahl() public static Bsp create() return new Anwendungsorientierte Programmierung } } Bsp(); Bsp obj1, obj2, obj3; obj1 = new Bsp(); obj1.printAnzahl(); // 1 obj2 = Bsp.create(); obj3 = obj2.create(); // ??? obj1.printNr(); // 1 obj2.printNr(); // 2 obj3.printNr(); // 3 obj1.printAnzahl(); // 3 obj2.printAnzahl(); // 3 obj3.printAnzahl(); // 3 Folie 76 7.1 Schreiben eigener Klassen Anwendungsorientierte Programmierung Folie 77 7.1 Schreiben eigener Klassen Datenaustausch durch statische Variablen (bei mehreren Threads sind weitere Maßnahmen erforderlich) class ProdCons { private static int puffer; public void store(int n) { Puffer = n; } public int get() { return puffer; } } ProdCons pc1 = new ProdCons(), pc2 = new ProdCons(); pc1.store(5); System.out.println(pc2.get()); // 5 Anwendungsorientierte Programmierung Folie 78 7.1 Schreiben eigener Klassen Die this Referenz. Mit dem Schlüsselwort this wird auf die aktuelle Klasseninstanz verwiesen. Hiermit können Namensverwechslungen aufgelöst werden public class NameClash { public String name public setName(String name) { this.name = name; } public copyName(NameClash that) { this.name = that.name; } } In statischen Methoden ist die Verwendung von this nicht erlaubt. Anwendungsorientierte Programmierung Folie 79 7.1 Schreiben eigener Klassen Der Konstruktor Für alle mit new angelegten Objekte muss entsprechender Speicherplatz angelegt werden. Hierbei wird automatisch ein Konstruktor aufgerufen. Für jede Klasse wird immer ein Konstruktor der Form public Klassenname() {} // der Standard-Konstruktor erzeugt. Alle Attribute werden mit 0, 0.0 bzw. null belegt. Parametrisierter Konstruktor Es ist möglich, eigene Konstruktoren zu erstellen. Konstruktuktoren können dann mit Parametern versehen werden. Damit lassen sich bestimme Attribute gezielt setzen. Konstruktoren können überladen werden. Eine Sonderstellung nimm ein Konstruktor ein, der als Parameter die Klasse selbst enthält. Meist wird dieser dazu eingesetzt, eine Kopie eines Objekts zu erstellen. Falls eigene Konstruktoren erstellt werden, so fügt der Compiler kein StandardKonstruktor mehr ein. Wird dieser benötigt, so muss er manuell hinzugefügt werden. Anwendungsorientierte Programmierung Folie 80 7.1 Schreiben eigener Klassen public class NameAge { public NameAge() {} // Standard-Konstruktor public NameAge(String name) { this.name = name; } public NameAge(NameAge toCopy) { // Copy-Konstruktor this.name = toCopy.name; this.age = toCopy.age; } static NameAge read(InputStream istream) { NameAge ret = new NameAge(); // einlesen; statische Methode als Pseudokonstruktor return ret; } // setter, getter private String name; private int age; } Anwendungsorientierte Programmierung Folie 81 7.1 Schreiben eigener Klassen Initialisierung von Attributen public class NameAge { public NameAge() {} // Standard-Konstruktor // setter, getter public void printMbrNr() { System.out.println("Nr: " + MBR_NR); } private static memCnt = 1; wird in den Konstruktor einkopiert private final int MBR_NR = memCnt++; private String name; private int age; } Der Modifizierer final bei Attributen bewirkt, das diese Attribute nur einmal zugewiesen werden können. Es handelt sich um eine Art von Konstanten. Diese sollten groß geschriebenen werden und können public sein. Anwendungsorientierte Programmierung Folie 82 7.2 Ableiten von Klassen Durch die Angabe extends wird eine Klasse aus einer anderen abgeleitet Beispiel public class Base { // Basisklasse, Oberklasse … } public class Sub1 extends Base {// Unterklasse, abgeleitete Klasse … } public class Sub2 extends Base { … } Hierdurch erhält jede Unterklasse alle Attribute und Methoden der Oberklasse. Werte und Konstruktoren werden nicht vererbt. Anwendungsorientierte Programmierung Folie 83 7.2 Ableiten von Klassen Es kann beliebig viele Hierarchiestufen geben Jede abgeleitete Klasse (Unterklasse) ist auch vom Typ der Oberklasse class A class BA extends A A a = new DCA(); mit instanceof kann der Typ geprüft werden a instanceof a instanceof a instanceof a instanceof a instanceof A // true CA // true DCA // true ECA // false BA // false Anwendungsorientierte Programmierung class CA extends A class DCA extends CA class ECA extends CA In Java sind alle Klassen vom Typ Object Folie 84 7.2 Ableiten von Klassen Es kann durch Typkonvertierung der ursprüngliche Datentyp zurück gewonnen werden Beispiel: public class Base { } public class Spec1 extends Base { public void print() {… } } public class Spec2 extends Base { public void write() {… } } Base[] basefeld; // gefüllt mit Spec1 oder Spec2 … if (basefeld[i] instanceof Spec1) ((Spec1)basefeld[i]).print(); if (basefeld[i] instanceof Spec2) ((Spec2)basefeld[i]).write(); Anwendungsorientierte Programmierung Folie 85 7.2 Ableiten von Klassen Modifizierer private, protected, public und Sichtbarkeitsregeln private: Innere Klassen, Attribute und Methoden sind nur innerhalb der Klasse sichtbar. Allerdings dürfen innere Klassen auf private Methoden und Attribute der umgebenden Klasse zugreifen. kein Modifizierer: beschreibt die Paketsichtbarkeit. Klassen, Attribute und Methoden sind nur innerhalb des gleichen Pakets sichtbar und zugreifbar. protected: Innere Klassen, Attribute und Methoden haben Paketsichtbarkeit und sind in allen abgeleiteten Klassen (auch in anderen Paketen) sichtbar. public: Klassen, Attribute und Methoden sind überall sichtbar. Die Sichtbarkeit von Elementen ist ein Teil des Entwurfs und sollte überlegt eingesetzt werden. Grundsätzlich sollte die Sichtbarkeit so eng wie möglich gesetzt werden. Anwendungsorientierte Programmierung Folie 86 7.2 Überschreiben (Polymorphie) Enthält eine Oberklasse eine Methode mit gleichem Namen und gleicher Signatur wie eine abgeleitete Klasse, so wird diese Methode überschrieben. Wird bei einem Objekt diese Methode aufgerufen so wird immer die in der Hierarchiestufe am nächsten stehende Methode aufgerufen. Bem.: Es können auch Attribute überschrieben werden (wenig sinnvoll) public class AType { public void print() { System.out.println("Ich bin ein A"); } } public class BType extends AType { public void print() { System.out.println("Ich bin ein B"); } } AType aInst = new AType(); AType bInst = new BType(); aInst.print(); // Ich bin ein A bInst.print(); // Ich bin ein B Anwendungsorientierte Programmierung Folie 87 7.2 Überschreiben public class Base { public void hair(double x) { System.out.println("Short hair"); } } public class Extensions extends Base { public void hair(int x) { System.out.println("Long hair"); } } Base kopf1 = new Extensions(); Extensions kopf2 = new Extensions(); kopf1.hair(3.1); // Short hair kopf1.hair(3); // Short hair kopf2.hair(3.1); // Short hair kopf2.hair(3); // Long hair Anwendungsorientierte Programmierung Lösung: Direktive @Override vor der Methode einfügen Folie 88 7.2 Super Eine überschriebene Methode (oder überschriebenes Attribut) kann über die vordefinierte Referenz super wieder aktiviert werden public class Basis { public void print() { System.out.println("Basis"); } } public class Lower extends Basis { @Override public print() { System.out.println("Lower"); } public superPrint() { super.print(); } } … Basis lower = new Lower(); lower.print() // Lower lower.superPrint() // Basis Anwendungsorientierte Programmierung Folie 89 7.3 Abstrakte Klassen Abstrakte Klassen und Methoden • oft kann es sinnvoll sein, in einer Oberklasse lediglich zu deklarieren, welche Methode alle Unterklassen aufweisen sollen ohne diese in der Oberklasse auszuprogrammieren. • eine solche Klasse heißt abstrakt • Von einer solchen Klasse kann kein Objekt mit new erzeugt werden, da bestimmte Methoden nicht ausführbar sind. Damit diese Klasse verwendbar wird, muss es eine nicht abstrakte Unterklasse geben, die alle abstrakten Methoden der Oberklassen ausprogrammieren. Anwendungsorientierte Programmierung Folie 90 7.3 Abstrakte Klassen Die Deklaration erfolgt durch das Schlüsselwort abstract public abstract class Basis { public abstract void methode(); // die Methode erhält keinen Rumpf } Falls eine Klasse eine abstrakte Methode enthält, so muss die Klasse ebenfalls abstrakt sein. Aus einer abstrakten Klasse können weitere abstrakte Klassen abgeleitet werden, die einige (oder alle) abstrakten Methoden abstrakt lassen. Anwendungsorientierte Programmierung Folie 91 7.3 Abstrakte Klassen public abstract class Knoten { private int index; public abstract double eval(); } public class Add extends Knoten { private Knoten leftOp; private Knoten rightOp; public double eval() { return leftOp.eval() + rightOp.eval(); } } public class Wert extends Knoten { private wert; public double eval() { return wert; } } Anwendungsorientierte Programmierung Folie 92 7.4 Finale Klassen und Methoden In bestimmten Situationen soll das Ableiten von Unterklassen und das Überschreiben von Methoden verhindert werden. Deklaration einer finalen Klasse public final class ThisIsTheEnd { … } Die nachfolgende Deklaration ist daher unzulässig public class SoNicht extends ThisIsTheEnd {…} Deklaration einer finalen Methode public class Klasse { public final void bitterEnd(){…} } public class UnterKlasse extends Klasse { @Override public void bitterEnd(){… } // unzulässig } Anwendungsorientierte Programmierung Folie 93 7.5 Konstruktoren Wird ein neues Element einer Unterklasse erzeugt, so werden für alle Unterklassen die Standardkonstruktoren in der Hierarchiereihenfolge ausgeführt. public class Base {…} public class Level1 extends Base {…} public class Level2 extends Level1 {…} public class Level3 extends Level2 {…} durch eine Anweisung Level1 item = new Level3(); wird ein neues Objekt folgendermaßen erzeugt: Konstruktion Object() (alle Java-Objekte sind vom Typ Object) Konstruktion Base() Konstruktion Level1() Konstruktion Level2() Konstruktion Level3() und Rückgabe der Referenz an item Anwendungsorientierte Programmierung Folie 94 7.5 Konstruktoren Wird bei der Deklaration einer Klasse C ein parametrisierter Konstruktor angegeben, so entfällt der Standardkonstruktor. Daher kann eine von C abgeleitete Klasse D nicht mehr eindeutig konstruiert werden. public class C { public C(int n) {…} } public class D extends C{ // Fehlermeldung: Implicit super constructor C() is undefined … } Lösungen: – Manuelles Einfügen eines Standardkonstruktors in der Klasse C – Aufruf eines parametrisierten Konstruktors von C durch super(…) public class D { public D() { super(1); } // Ausführen von C(int n) } // super(…) muss immer die erste Anweisung sein Anwendungsorientierte Programmierung Folie 95 7.6 Schnittstellen (Interfaces) Schnittstellen sind Klassenbeschreibungen, die nur – abstrakte Methoden (ohne Angabe von abstract) und – finale statische Attribute (ohne Angabe von public static final, Konstanten) beinhalten Es wird kein ausführbarer Quelltext vererbt (sog. Schnittstellenvererbung) Deklaration: interface statt class Anwendungsorientierte Programmierung Folie 96 7.6 Schnittstellen (Interfaces) Beispiele public interface Position { void setPoint(double x, double y); } public interface GeoObjekt { double flaeche(); double umfang(); } Anwendungsorientierte Programmierung Folie 97 7.6 Schnittstellen (Interfaces) Interfaces verwenden (implementieren) – Schnittstellen sind ähnlich wie Oberklassen. Anstatt mit extends wird diese mit implements angegeben public class Punkt implements Position { … } – Im Gegensatz zu Oberklassen kann eine Klasse mehrere Schnittstellen implementieren (Mehrfachvererbung) public class Rechteck implements Position, GeoObjekt { … } – Wird eine Methode einer Schnittstelle nicht ausprogrammiert, so ist die Klasse abstrakt Anwendungsorientierte Programmierung Folie 98 7.6 Schnittstellen (Interfaces) Eine Klasse kann gleichzeitig abgeleitet werden und Schnittstellen implementieren public class Computer { … } public class GPSEmpfänger extends Computer implements Position { … } Die Klasse GPSEmpfänger ist sowohl vom Datentyp Computer als auch Position Schnittstellen können abgeleitet werden public interface GeoObjektPlus extends GeoObject { Punkt getSchwerpunkt(); } Anwendungsorientierte Programmierung Folie 99 7.7 Innere Klasse Klassen können innerhalb einer anderen Klasse deklariert werden Gründe: – Strukturierung – sollen nicht lokal sichtbar sein – insbesondere in der GUI-Programmierung elegante Technik, um den Quelltext übersichtlich zu halten Sichtbarkeitsmodifikatoren (private etc.) sind zulässig innere Klassen können auf Attribute und Methoden der äußeren Klasse zugreifen Anwendungsorientierte Programmierung Folie 100 7.7 Innere Klassen public class Spieler { private Stein stein; Spieler (int wert) { stein = new Stein(wert); } private class Stein { int wert; Stein(int wert) { this.wert = wert; } } int nenneWert() { return stein.wert; } } Anwendungsorientierte Programmierung Folie 101 7.7 Innere Klassen class Aussen { Innen inner; … class Innen { int y; … } } Deklaration: Aussen.Innen abc; Zugrifff: Aussen inst; inst.inner.y = 17; Anwendungsorientierte Programmierung Folie 102 7.7 Varianten von inneren Klassen • Lokale Klassen werden innerhalb von Methoden oder Blöcken deklariert • Anonyme Klassen lokale Klassen können ohne Namen bleiben als Implementation einer Schnittstelle • Statische innere Klassen wenn die innere Klasse auch ohne Instanzen der äußeren Klasse Instanzen haben soll Anwendungsorientierte Programmierung Folie 103 7.8 Modellierung der Daten Unterschiedliche Arten von Datenstrukturen Beispiel: Graph Datenstrukturen zur Verwaltung: 1 • Liste von Knoten • Liste von Kanten 6 2 5 3 4 Anwendungsorientierte Programmierung Datenstrukturen für die Information Knoten Index, Farbe Vorgänger, Nachfolger (Nachbar) Kanten Von, Nach bzw. K1, K2 Folie 104 7.8 Modellierung der Daten Möglichkeiten der Modellierung von Daten Ableiten Implementieren von Interfaces Komposition • Aggregation • Bekanntschaft Verwendung von Entwurfsmuster E.Gamma, R. Helm, R. Johnson, J. Vlissides Design Pattern, Elements of Reusable Object-Oriented Software Addison Wesley Anwendungsorientierte Programmierung Folie 105 7.8 Modellierung der Daten Ableiten public class Ware { protected int preis; protected int teileNr; } public abstract class Blumen extends Ware { abstract public String pflegeAnleitung(); } public class Rohre extends Ware { public double abmessung; } public class UsambaraVeilchen extends Blumen { … } … Anwendungsorientierte Programmierung Folie 106 7.8 Modellierung der Daten Verwendung von Interfaces interface Orderable { void setPreis(double p); double getPreis() } public class Blumen implements Orderable{ private double preis; public void setPreis() { … }; // usw. } public class Rohre implements Orderable { private double preis; public void setPreis() { … }; // usw. } public class Usambaraveilchen extends Blumen {…} … Anwendungsorientierte Programmierung Folie 107 7.8 Modellierung der Daten Komposition: Hier Aggregation (Lebenszeit des zugeordneten Objekts ist gleich der des übergeordneten Objekts) public abstract class Inf { public abstract String showInf(); } public class Abmessungen extends Inf { public String showInf() { … } } public class Pflegeanleitung extends Inf { … } public abstract class Blumen …{ private Inf inf = new Pflegeanleitung(); } public class Rohre …{ private Inf inf = new Abmessungen(); } Anwendungsorientierte Programmierung Folie 108 7.8 Modellierung der Daten Komposition: Bekanntschaft (Die referenzierten Objekte sind unabhängig) public class PreisListe { public void setPreis(int nr, double ezp) { … } public double getPreis(int nr) { … } } public class Blumen { protected PreisListe plRef; // jede Ware erhält eine Referenz public Blumen(Preisliste pl) { plRef = pl; } } public class UsambaraVeilchen extends Blumen { public UsambaraVeilchen(PreisListe pl) { super(pl); plRef.setPreis(id, 2.99); … } Anwendungsorientierte Programmierung Folie 109 7.2.1 Entwurfsmuster: Singleton Private Konstruktoren (Singletons) Konstruktoren können auch private deklariert werden. Damit wird verhindert, dass mehrere Objekte angelegt werden können public class Fujisan { private Fujisan() { aus = "富士山"; } public static Fujisan getFuji() { if (fuji = null) return (fuji = new Fujisan()); else return fuji; } private static Fujisan fuji = null; private String aus } Anwendungsorientierte Programmierung Folie 110 7.8 Modellierung der Daten Die Preisliste wird als Singleton implementiert public class PreisListe { private PreisListe pl … static PreisListe getPreisListe() { s.o. } public void setPreis(int nr, double ezp) { … } public double getPreis(int nr) { … } } public class Blumen { … } public class UsambaraVeilchen extends Blumen { public UsambaraVeilchen() { // keine Referenz notwendig PreisListe.getPreisListe().setPreis(id, 2.99); … } Anwendungsorientierte Programmierung Folie 111 7.2.2 Entwurfsmuster: Factory public abstract class Produzent { // oder interface public static Produzent create(String gebaeude) { switch (gebaeude) { case "Schmiede" : return new Schmiede(); case "Bauernhof" : return new Bauernhof(); default: // Fehlerbehandlung } } public abstract void produce(); } public class Schmiede extends Produzent { public void produce() { System.out.println("Werzeuge"); } } public class Bauernhof extends Produzent { public void produce() { System.out.println("Weizen"); } } Anwendungsorientierte Programmierung Folie 112 8.1 Entwurfsmuster: Factory public static void main() { Produzent[] produzenten = new Produzent[3]; produzenten[0] = Produzent.create("Schmiede") produzenten[1] = Produzent.create("Bauernhof"); produzenten [2] = Produzent.create("Bauernhof"); for (Produzent p : produzenten) { p.produce(); } } // Ausgabe Werkzeuge Weizen Weizen Anwendungsorientierte Programmierung Folie 113 7.2 Modellierung der Daten Einfügen eines Bestellformulars public class Formular { … public static Formular generateOrderForm(String typ) { … } } public class UsambaraVeilchen { private Formular of = Formular.generateOrderForm("Usambara") { // Daten können beispielweise aus einer Datei eingelesen // werden } public class VierkantStahlrohr { public Formular of = Formular.generateOrderForm("20x20") { } Anwendungsorientierte Programmierung Folie 114 7.3 Generische Klassen Motivation eine datenhaltende Klasse kann nur eine Art von Information speichern. was ist, wenn wir unterschiedliche Informationen speichern wollen? mehrere fast identische Klassen müssen geschrieben werden! oder: nur Datentyp Object, aber dann fehlt die Kontrolle über die Konsistenz der gespeicherten Daten Anwendungsorientierte Programmierung Folie 115 7.3 Generische Klassen Idee: Generizität Vorbild: bei den Feldern wird ein Basisdatentyp angegeben String[] namen; Danach ist klar: namen[i] sind vom Typ String Idee: Klassendefinition mit einem Typparameter T versehen class Liste < T > {. . . } T wird innerhalb der Klasse wie ein normaler Typ (als Stellvertreter) benutzt Anwendungsorientierte Programmierung Folie 116 7.3 Generische Klassen Eigene generische Klassen schreiben public class Paar<Typ> { private Typ l, r; public Paar<Typ>(Typ l, Typ r) { this.l = l; this.r = r; } public Typ getL() { return l; } public Typ getL() { return l; } public String toString() { return ("(" + l.toString + "," + r.toString +")"); } } Anwendungsorientierte Programmierung Folie 117 7.3 Generische Klassen Verwendung generischer Klassen – bei der Deklaration von Variablen/Attributen: der konkrete Typ wird angegeben Paar<String> paar; – auch beim Konstruktor wird der konkrete Datentyp angegeben paar = new Paar<String>("A", "B" ); – öffentliche Methoden (und Attribute) werden einfach so benutzt, als ob die Klasse normal deklariert wäre Anwendungsorientierte Programmierung Folie 118 7.3 Generische Klassen Verwenden generischer Klassen Paar<String> assoz = new Paar<String >(" Tiger " , " Indien"); String s = assoz. getL ( ) : System .out.println( assoz) ; Paar<Integer> quad = new Paar<Integer > ( new Integer( 7 ) , new Integer( 49) ) ; int i = quad.getR( ).intValue( ) ; Achtung! Es dürfen keine primitiven Datentypen verwendet werden. (Für primitive Datentypen werden dann die Wrapper-Typen benutzt) Anwendungsorientierte Programmierung Folie 119 7.3 Generische Klassen Basisdatentyp auf Unterklassen einschränken: public class Paar<T extends Comparable> {…} Für T sind nur noch Unterklassen von Comparable zulässig vom Basisdatentyp unabhängige Methode: public static void paarAusgeben(Paar<?> p) {…} . . . und eingeschränkt: public static void paarVergleich(Paar<? extends Comparable> p) {…} public static void methode(Paar<? super Comparable> p) {…} Anwendungsorientierte Programmierung Folie 120 7.3 Generische Klassen statische Methoden mit generischem Parameter: public static <T> T links(Paar<T> p) { … } public static <T, S extends T> T test(Paar<T> p, S x) { … } generische Parameter werden beim Aufruf nicht angegeben. Sie sind nur bei der Definition relevant Anwendungsorientierte Programmierung Folie 121 7.4 Überschreiben von bestimmten Methoden Sollen die Instanzen einer Klasse verglichen werden, so muss das Interface Comparable<T> implementiert werden. Hierzu wird die Methode int compareTo(T to) implementiert. Diese liefert ein Ergebnis <0 == 0 >0 falls this < to falls this == to falls this > to Anschließend können dann Felder oder Listen mit Instanzen dieser Klasse mit der Methode sort() sortiert werden. Eventuell müssen auch die Methode equals(T to) und hashCode() überschrieben werden. Diese Methoden können in der IDE unter dem Menüpunkt Source automatisch generiert und anschließend modifiziert werden Anwendungsorientierte Programmierung Folie 122 8 Java-Collections-Framework In Java gibt es vorgefertigte generische Klassen (in java.util.*) , um Mengen von Daten zu verwalten. Diese werden als Collections bezeichnet. Diese Klassen bieten viele Vorteile – meist wesentlich effizienter als eigene Implementierung – der Code ist bereits getestet – das Programm wird lesbarer daher ist es ratsam, die Collections zu verwenden generische Interfaces geben die verfügbaren Methoden an abhängig von der Implementierung werden die Daten unterschiedlich organisiert Anwendungsorientierte Programmierung Folie 123 8 Java-Collections-Framework Interfaces der Collections List geordnete Zusammenfassung von Elementen Duplikate sind erlaubt Zugriff über Index Set unsortierte Menge von Elementen keine Duplikate erlaubt Map Zuordnungen: Elemente Schlüssel Schlüssel sind eindeutig Deque Einfügen/Entnehmen amAnfang/Ende z.B. für FIFO/LIFO-Schlangen Anwendungsorientierte Programmierung Folie 124 8 Java-Collections-Framework Das Interface Collection<T> Alle Klassen des Frameworks implementieren diese Schnittstelle. Daher sind immer folgenden Methoden vorhanden (Auszug) boolean add(T e) fügt ein Elemente hinzu; true, falls e sich einfügen lässt boolean addAll(Collection <? extends T> c) fügt alle Elemente aus c hinzu void clear() Löscht alle Elemente (optional) boolean contains(Object o) true, falls o vorhanden boolean isEmpty() true, falls der Container leer ist boolean remove(Object o) Löscht das Objekt o; true falls vorhanden boolean removeAll(Collection c) Löscht alle in c enthaltenen Elemente int size() Liefert die Anzahl der Elemente Object[] toArray() Speichert alle Elemente in einem Feld Iterator<T> iterator() (geerbt von Iterabel) Objekt zum iterieren im Container Anwendungsorientierte Programmierung Folie 125 8 Java-Collections-Framework Einige Methoden sind optional. Da aber jede Klasse die entsprechende Methode implementieren muss, wird dieser Fall durch das Auslösen von UnsupportedOperationException gelöst. Diese wird auch bei unzulässigen Aktionen ausgelöst. equals() Klassen, die in Collections verwendet werden, sollten, durch überschreiben, eine geeignete Methode equals() implementieren. Viele Methoden wie contains, remove verwenden diese Methode zum Vergleich. Anwendungsorientierte Programmierung Folie 126 8 Java-Collections-Framework Die Ableitungsstruktur weiterer Interfaces Interface Iterable liefert Iterator Interface Collection Interface: Queue Schlangen/FIFO Interface: List Interface für Listen/Sequenzen Interface: Deque zweiseitig Interface: ArrayList Interface: LinkedList Anwendungsorientierte Programmierung Interface: Set Mengen Map ist eine weitere Schnittstelle, die zur Verwaltung von Assoziationen (Schlüssel,Wert) verwendet wird Folie 127 8 Java-Collections-Framework Implementierungen (Klassen) List (Listen) Set (Mengen) Map Queue ArrayList Liste als Feld LinkedList Doppelt verkettete Liste HashSet implementiert Menge durch schnelle Hash-Verfahren TreeSet Elemente sind sortiert, implementiert Menge als Baum LinkedHashSet sortiert, schnelles Hash-Verfahren HashMap Assoziationen durch Hash-Verfahren TreeMap Assoziationen durch Baum, sortiert LinkedHashMap Hash-Verfahren, sortiert WeekHashMap Elemente können entfernt werden LinkedList s.o. ArrayBlockingQueue Blockierenden Warteschlange PriorityQueue Prioritätswarteschlange Anwendungsorientierte Programmierung Folie 128 8 Java-Collections-Framework List<T> zusätzliche Methoden T get( int index); wahlfreier lesender Zugriff auf ein Element T set(int index, T element); wahlfreier schreibender Zugriff auf ein Element void add(int index, T element); fügt ein Element an der Stelle index ein. Die Nachfolger werden verschoben. T remove(int index) entfernt das Element an der Stelle index. Die Nachfolger werden nach vorn verschoben. List<T> sublist (int fromIndex, int toIndex) erzeugt eine Teilliste mit den angegebenen Elementen Anwendungsorientierte Programmierung Folie 129 8 Java-Collections-Framework Implementierung LinkedList<T> verkette Liste. Wahlfreier Zugriff langsam. Kein Speicher-Overhead. Konstruktor für eine leere Liste: public LinkedList<T>(); Wird wie folgt verwendet: List<Typ> liste = new LinkedList<Typ>(); Konstruktor für mit Elementen vorbelegte Liste: public LinkedList(Collection<? extends T> c); ArrayList<T> Realisierung durch ein Feld. Schneller wahlfreier Zugriff. Speicher-Overhead. Bei Größenänderung muss evtl. das gesamte Feld umkopiert werden. Konstruktor für eine leere Liste List<Typ> liste = new ArrayList<Typ>(); Alle weiteren analog zu LinkedList Anwendungsorientierte Programmierung Folie 130 8 Java-Collections-Framework Set<T> Gleiche Methoden wie List, aber mit teilweise anderer Semantik, da keine doppelten Einträge erlaubt sind (z. B. add(T e)). TreeSet<T> speichert die Elemente in einer Baumstruktur. Die Elemente werden in sortierter Reihenfolge abgelegt HashSet<T> speichert die Elemente in einer sog. Hash-Tabelle. Dies erfolgt schneller als in TreeSet, die Elemente sind aber nicht sortiert. Beim Hash-Verfahren wird die in Object definierte Methode hashCode() benutzt, um die Speicherstelle zu identifieren. Anwendungsorientierte Programmierung Folie 131 8 Java-Collections-Framework Deque<T> Datenstruktur für FIFOs, Stapel und Warteschlangen. Effizienter Zugriff auf das erste und letzte Element in einer Liste. Methoden: void addLast(T e) fügt ein Element am Ende ein T removeLast() löscht letztes Element und gibt es zurück T getLast() gibt letztes Element zurück void addFirst(T e) fügt Element am Anfang ein T removeFirst() löscht erstes Element und gibt es zurück T getFirst() gibt erstes Element zurück Anwendungsorientierte Programmierung Folie 132 8 Java-Collections-Framework Map<K, V> Methoden des Interfaces Map<K,V>: V put(K key, V value) erzeugt eine neue Verknüpfung (und gibt den bisherigen Wert zum Schlüssel zurück (null bei einer neuen Verknüpfung). Bei value kann es sich um einen beliebigen (auch komplexen) Datentyp handeln. V get(Object key) liefert den Wert zum Schlüssel (null falls keineVerknüpfung vorhanden ist) boolean containsKey(Object key) prüft, ob der Schlüssel enthalten ist Anwendungsorientierte Programmierung Folie 133 8 Java-Collections-Framework Methoden von Map (Fortsetzung) boolean containsValue(Object value) prüft, ob der Schlüssel enthalten ist Set<K> keySet() liefert die Menge der verwendeten Schlüssel Collection<V> values() liefert eine Liste mit den verwendeten Werten Anwendungsorientierte Programmierung Folie 134 8 Java-Collections-Framework Implementierungen HashMap<K, V> speichert die Elemente in einer sog. Hash-Tabelle. Der Zugriff ist in (fast) konstanter Zeit möglich. Die Elemente liegen unsortiert vor. TreeSet<K, V> speichert die Elemente in einer Baumstruktur. Die Elemente werden in sortierter Reihenfolge abgelegt. Die Methoden von TreeSet sind meist langsamer als die von HashMap. Anwendungsorientierte Programmierung Folie 135 8 Java-Collections-Framework Iteratoren jede Collection hat die Methode Iterator<T> iterator() diese liefert ein Objekt, mit dem man alle Elemente in der Collection aufzählen kann. Das Iterator-Interface: boolean hasNext() liefert true falls noch weitere Elemente vorhanden sind, false sonst. T next() Nächstes Element void remove() Löscht das zuletzt gelieferte Element Anwendungsorientierte Programmierung Folie 136 8 Java-Collections-Framework Beispiel: Iteratoren List<String> liste = new LinkedList<String>(); for (int i = 0; i < 5; i++) liste.add("Elem" + i); System.out.println(liste); // [Elem0, Elem1, Elem2, Elem3, Elem4] Iterator<String> it = liste.iterator(); boolean loeschen = false; while (it.hasNext()) { if (loeschen) it.remove(); loeschen = !loeschen; } System.out.println(liste);// [Elem0, Elem2, Elem4] Anwendungsorientierte Programmierung Folie 137 8 Java-Collections-Framework Verallgemeinerte ForSchleife alle Collections-Klassen können auch mit einem impliziten Iterator in der foreachSchleife benutzt werden Bsp.: List<String> liste = new LinkedList<String>() . . . for ( String s : liste) System.out.println(s); Anwendungsorientierte Programmierung Folie 138 9 Graphische Benutzeroberflächen Einige Vorbemerkungen Regel für graphische Benutzeroberflächen (GUI) Der Aufbau und die Gestaltung soll auf die Bedürfnisse des Benutzers zugeschnitten sein und nicht den Programmierkenntnissen des Programmierers entsprechen. Trennung von GUI und Programmlogik Hier sollen vor allem die Pakete java.awt und javax.swing benutzt werden Kennzeichen: objektorientierter Ansatz – Fenster und Dialogelemente sind Objekte – Interaktion wird durch Objekte und deren Methoden realisiert Anwendungsorientierte Programmierung Folie 139 9 Graphische Benutzeroberflächen Fenstertypen • Fenster mit Titelleiste und eventuell Menüleiste (z. B. Das Hauptfenster) javax.swing.JFrame • Dialoge für Ausgaben oder Benutzerinteraktionen javax.swing.JDialog Diese Fenster können modal sein, d. h. alle weiteren Eingaben sind blockiert bis des Dialog geschlossen wird • Fenster ohne Titelleiste javax.swing.JWindow • Applets javax.swing.JApplet Allen Fenstern kann eine Größe und ein Ursprung (relativ zum übergeordneten Fenster) zugeordnet werden. Die Größe kann veränderbar oder fest vorgegeben werden Fenster und ihre Inhalte werden erst durch setVisible(true) sichtbar. Anwendungsorientierte Programmierung Folie 140 9 Graphische Benutzeroberflächen JFrame Title (setTitle()) Decorated(setDecorated(true/false) Größe (setSize(b, h)) Ort (setLocation(x, y) ContentPane Anwendungsorientierte Programmierung Folie 141 9 Graphische Benutzeroberflächen Benutzung von JFrame Methoden (Auswahl) • JFrame(): Erzeugen eines (unsichtbaren) Fensters • JFrame(String titel) : Fenster mit Titel titel • setTitle(String titel): Titel ändern • setResizable(boolean status): Größe veränderbar? • setVisible(boolean status): sichtbar (Fenster sind bei der Generierung unsichtbar) • setDefaultCloseOperation(int operation): Aktion beim Schließen – WindowConstants.DO_NOTHING_ON_CLOSE: nichts – JFrame.EXIT_ON_CLOSE: Schließen der Anwendung • setSize(int b, int h): Größe des Fensters (Breite b, Höhe h) • setLocation(int x, int y): Position des Fensters • pack() Größe automatisch einstellen Anwendungsorientierte Programmierung Folie 142 9 Graphische Benutzeroberflächen Anzeigen von Inhalten und Bedienelementen Die Anzeige erfolgt über sogenannte Widgets. Das sind Klassen, die für eine bestimmte Anwendung vorgesehen sind. (Auswahl) – JLabel: reine (meist unveränderte) Textanzeige – JTextField: Ein- / Ausgabe einer Textzeile – JTextArea: Ein- / Ausgabe von beliebigem Text (z. B. Editor) – JButton: Schaltflächen – JSlider: Schieberegeler – und viele mehr Anwendungsorientierte Programmierung Folie 143 9 Graphische Benutzeroberflächen Widgets: JLabel reine (meist unveränderte) Textanzeige • JLabel( String text ): neues Label erzeugen und mit dem angegeben Text belegen • JLabel( String text , int orient ): neues Label mit Orientierung des Textes • getText(): liefert den Text • setText( String text ): ändert den angezeigten Text Anwendungsorientierte Programmierung Folie 144 9 Graphische Benutzeroberflächen Widgets: JTextField / JTextArea Ein-/Ausgabe von Text • JTextField (int zeichen): neues Textfeld mit der Breite von zeichen • JTextField ( String anfangstext , int zeichen): dito mit Text • getText(): liefert den Text • setText( String text ): ändert den angezeigten Text • boolean isEditable (): Ist der Text nutzeränderbar? • setEditable (boolean status): ändert obige Einstellung • setHorizontalAlignment (int ausrichtung): Textausrichtung Anwendungsorientierte Programmierung Folie 145 9 Graphische Benutzeroberflächen Widgets: JButton Schaltflächen • JButton(): erzeugt eine Schaltfläche • JButton(String text ): dito mit Text • setText(String s): ändert den Text • addActionListener ( ActionListener a): zu benachrichtigendes Objekt bei Nutzerinteraktion (dazu später) Anwendungsorientierte Programmierung Folie 146 9 Graphische Benutzeroberflächen Weitere Widgets • Checkboxen (JCheckBox) • Radiobuttons (JRadioButton und ButtonGroup) • Auswahlliste ( JList ) • Combobox (JComboBox) • Schieberegler ( JSlider ) • Fortschrittsbalken (JProgressBar) • Menüleisten (JMenuBar, JMenu, JMenuItem) • Pop-Up-Men•us (JPopUpMenu) • Tabellen (JTable und TableModel) • Baumdarstellungen (JTree und TreeModel) Anwendungsorientierte Programmierung Folie 147 9 Graphische Benutzeroberflächen Die so erstellten Widges können in das Fenster eingefügt werden • Durch add(Component c) (ab Java 5.0) • Jedes Fenster hat einen Darstellungsbereich die ContentPane – getContentPane(): liefert den Darstellungsbereich. Bsp: Container cp = wnd.getContentPane() // wnd ist von JFrame //abgeleitet cp.add(widget) – setContentPane(Container c): setzt eine neuen Darstellungsbereich – setBounds(int x, int x, int b, int h): kann das Widget an der Position x, y mit Größe b, h platziert werden Anwendungsorientierte Programmierung Folie 148 9.1 Erstellen von GUIs (Graphical User Interface) Manuelle Platzierung der Elemente 10, 10 20 80 Anwendungsorientierte Programmierung public class Application extends JFrame { JButton okBtn; JTextField text; public Application() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container cp = getContentPane(); setSize(100,150); JPanel panel = new JPanel(); panel.setLayout(null); text = new JTextField("TEXT"); panel.add(text); text.setBounds(10, 10, 80, 20); okBtn = new JButton("ok"); panel.add(okBtn); okBtn.setBounds(10, 60,80,20); cp.add(panel); } } Folie 149 9.1 Graphische Benutzeroberflächen Verwaltung der Widgets JPanel: Für ein Layout der Komponenten müssen diese gruppiert werden. • JPanel(): erzeugt einen Container mit Flow-Layout • JPanel(LayoutManager layout): erzeugt Container mit anderem Layout • setLayout(LayoutManager): setzt ein Layout • add(Component): fügt ein Widget hinzu Anwendungsorientierte Programmierung Folie 150 9.2 Ereignisbehandlung Behandlung von Events • mit addActionListener Objekt zur Ereignisbehandlung anmelden • Objekt muss Schnittstelle ActionListener implementieren • genauer: Methode public void actionPerformed(ActionEvent event) • drei Ansätze: – Fenster implementiert ActionListener selbst – separate Klasse – eingebettete Klasse Anwendungsorientierte Programmierung Folie 151 9.2 Ereignisbehandlung in actionPerformed(ActionEvent event) kann auf das Ereignis zugegriffen werden: – getSource() liefert das Objekt, welches dasEreignis ausgelöst hat – getActionCommand() liefert z.B. die Zeichenkette, die in der Schaltfläche steht – getWhen() liefert einen Zeitstempel – getModifiers () liefert Information zu zusätzlich gedrückten Tasten (SHIFT MASK, CTRL MASK,ALT MASK etc.) Anwendungsorientierte Programmierung Folie 152 9.2 Ereignisbehandlung Beispiel: Fenster implementiert ActionListener selbst import java.awt.event.*; // Basisklassen für Events import javax.swing.*; public class InKlasse extends JFrame implements ActionListener { public InKlasse() { … JButton button = new JButton("Text"); //aktives Element add(button); button.addActionListener(this); //als Listener anmelden } public void actionPerformed(ActionEvent event) { // Wird aufgerufen falls der Knopf gedrückt wird } } Anwendungsorientierte Programmierung Folie 153 9.2 Ereignisbehandlung Der Listener wird durch eine eigene Klasse realisiert (Importe nicht angegeben) public class MeinListener implements ActionListener { private EigeneKlasse meinFenster; MeinListener(EigeneKlasse wnd) { meinFenster = wnd; } public void actionPerformed(ActionEvent event) { Object button = event.getSource() //Zugriff auf button String text = ((JButton)button).getText() //da die Quelle durch das Programm bekannt ist, //ist ein ungeprüfter Typecast zulässig if (text.equals("Aus") { ((JButton)button).setText("An"); meinFenster.incZaehler(); } else ((JButton)button).setText("Aus"); } } } Anwendungsorientierte Programmierung Folie 154 9.2 Ereignisbehandlung Zusammenfügen public class EigeneKlasse extends JFrame { privat int zaehler = 0; public void incZaehler() { zaehler++; } public EigeneKlasse () { JButton button = new JButton("Aus"); //aktives Element add(button); //Hinzufügen zum Fenster MeinListener action = new MeinListener(this); //Erstellen einer Behandlung button.addActionListener(action); //Anmelden an Button } } Anwendungsorientierte Programmierung Folie 155 9.2 Ereignisbehandlung Innere Klasse public class EigeneKlasse extends JFrame { privat int zaehler = 0; private JButton button; public EigeneKlasse () { button = new JButton("Aus"); //aktives Element button.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent event) { String text = button.getText() if (text.equals("Aus") { button.setText("An"); zaehler++; } else button.setText("Aus"); } } }); } } Anwendungsorientierte Programmierung Folie 156 9.2 Ereignisbehandlung Weitere Ereignisse • Ereignisse auf niedriger Ebene (low level events) – Maustasten und –bewegungen – Fokus: das Element wird aktiv – Tastendrücke – etc. • Semantische Ereignisse (high level events): Diese werden von GUI-Komponenten wie Schaltflächen, Rollbalken usw. ausgelöst. Hierbei werden meist Low level events in semantische Ereignisse umgewandelt. Die Komponente muss hierbei den Fokus haben, d. h. die Low level events werden zu dieser Komponente geleitet. Die Behandlung erfolgt ähnlich, daher wird hier keine Unterscheidung gemacht. Anwendungsorientierte Programmierung Folie 157 9.3 Verwendung von Layoutmanagern Jedes Element in Swing besitzt drei Größen MinimumSize, MaximumSize und PreferredSize durch getXXX wird die Größe durch ein Objekt der Klasse Dimension zurückgegeben. Ein Dimension-Objekt hat die öffentlichen Attribute width und height vom Typ int. Durch setXXX kann die Größe gesetzt werden. Beachte: die Methode setSize(int widtht, int height) hat, außer auf das Hauptfenster, keine Auswirkung FlowLayout JPanel cp = (JPanel)wnd.getContentPane(); JPanel flaeche = new JPanel(); JTextField tf = new TextField(); tf.setPreferredSize(new Dimension(70,15); flaeche.add(tf); JButton btn = new JButton("ok"); tf.setPreferredSize(new Dimension(70,15); flaeche.add(btn); pack(); Anwendungsorientierte Programmierung Folie 158 9.3 Verwendung von Layoutmanagern Automatisches Layout der Komponenten • FlowLayout : füllt zeilenweise die Widgets mit Umbruch falls notwendig • BorderLayout Einteilung in Bereiche Bereiche WEST, NORTH, EAST, SOUTH,CENTER bei add muss der Zielbereich angeben werden sinnvoll für grobe Einteilung auf höchster Fensterebene • BoxLayout: Die Elemente werden neben- oder übereinander platzieren Orientierung: X_AXIS, Y_AXIS, LINE AXIS bzw. PAGE AXIS • GridLayout: regelmäßiges Gitter • GridBagLayout: Für schwierige Fälle Anwendungsorientierte Programmierung Folie 159 9.3 Graphische Benutzeroberflächen Ein Beispiel Borderlayout NORTH CENTER EAST WEST SOUTH Jpanel BoxLayout, Y_AXIS Jpanel FlowLayout Anwendungsorientierte Programmierung Folie 160 9.3 Ereignisbehandlung Die Ereignisquellen und ihre Listener (awt) Listener Ereignisse ActionListener Drücken auf eine Schaltfläche oder <ret> in einem Textfeld Typ: ActionEvent WindowListener Schließen oder Verändern eines Fensters Typ: WindowEvent MouseListener Drücken auf eine Maustaste Typ: MouseEvent MouseMotionListener Bewegung der Maus Typ: MouseEvent Anwendungsorientierte Programmierung Folie 161 9.3 Ereignisbehandlung Fensterereignisse Schnittstelle: WindowsListener void windowOpened(WindowEvent event) Wird aufgerufen, wenn das Fenster geöffnet wird. void windowClosing(WindowEvent event) Wird aufgerufen, wenn das Fenster geschlossen wird. void windowClosed(WindowEvent event) Wird aufgerufen, wenn das Fenster mit dispose() beendet wird. void windowIconified(WindowEvent event) Wird aufgerufen, wenn das Fenster zum Icon verkleinert wird. void windowDeiconified(WindowEvent event) Wird aufgerufen, wenn das Fenster wieder vergrößert wird. void windowActivated(WindowEvent event) Wird aufgerufen, wenn das Fenster aktiviert wird. void windowDectivated(WindowEvent event) Wird aufgerufen, wenn das Fenster deaktiviert wird. Anwendungsorientierte Programmierung Folie 162 9.3 Ereignisbehandlung Da es sich bei WindowListener um eine Schnittstelle handelt, müssen alle Methoden implementiert werden. Häufig werden allerdings nur wenige Methoden benutzt, daher müssten alle anderen mit leeren Rümpfen dennoch mitgeführt werden. Verwendung von Adapterklassen java.awt.event.WindowAdapter Diese Klasse implementiert alle Methoden mit leeren Rümpfen Anwendungsorientierte Programmierung Folie 163 9.3 Ereignisbehandlung Verwendung public class CloseWindow { public static void main(String[] args) { JFrame wnd = new JFrame(); wnf.setSize(400, 400); wnd.setVisible(); wnd.addWindowListener(new CloseWindowAction()); } } public class CloseWindowAction extends WindowAdapter { @Override public void windowClosing(WindowEvent e) { System.exit(0); } } Anwendungsorientierte Programmierung Folie 164 9.3 Ereignisbehandlung Verwendung von inneren Klassen public class CloseWindow extends JFrame{ public CloseWindow() setSize(400, 400); addWindowListener( new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } } ) } public static void main(String[] args) { new CloseWindow().setVisible(true); } } Anwendungsorientierte Programmierung Folie 165 9.3 Ereignisbehandlung Die Ereignisse einer Komponente (JComponent) Ereignis Grund ComponentEvent Die Komponente wird bewegt, angezeigt, verdeckt oder verschoben FocusEvent bekommt oder veliert den Fokus MouseEvent Maus betritt oder verlässt den Bereich. Tastendruck, Bewegung InputMethodEvent Text- oder Cursor-Veränderung HirarchieEvent Änderung der Hierarchie PropertyChangeEvent Eine gebundene Eigenschaft ändert sich ContainerEvent Hinzufügen oder Löschen von Komponenten (Container) AncestorEvent Der Vorgänger wurde verändert Anwendungsorientierte Programmierung Folie 166 9.3 Ereignisbehandlung Auf Tastendrücke reagieren, der KeyListener (Schnittstelle) Methoden void keyTyped(KeyEvent e) Mit e.getKeyChar() kann das eingegebene Zeichen abgefragt werden. Handelt es sich nicht um ein gültiges Unicode-Zeichen so wird CHAR_UNDEFINED (65535) zurückgeliefert. void keyPressed(KeyEvent e) void keyReleased(KeyEvent e) Hierdurch können auch Sonderzeichen wie <F1> oder <Entf> abgefragt werden. Durch e.getKeyCode() wird eine Nummer für die gedrückte Taste zurückgeliefert. Die Nummern werden als virtueller Code (virtual key code) bezeichnet. Hierfür sind Konstanten die mit VK_ beginnen definiert. Beispiele: <F1> VK_F1 <Entf> VK_DELETE Anwendungsorientierte Programmierung Folie 167 9.3 Ereignisbehandlung Abschließende Bemerkungen • Es wurde hier nur ein kleiner Ausschnitt aus den Möglichkeiten für den Aufbau einer GUI (Graphical user interface) vorgestellt. • Mit Hilfe der vorhanden Klassen und Schnittstellen lassen sich beliebig komplexe Oberflächen schreiben. • Die Oberfläche richtet sich immer nach dem Benutzer • Der Entwurf und Implementierung einer guten GUI kann sehr zeitaufwendig sein und ist teilweise gleich oder höher als Entwurf und Codierung der eigentlichen Programmlogik Anwendungsorientierte Programmierung Folie 168 10 Serialisierung Die Objektzustände können gespeichert werden (persistent) Das Speichern von Objekten wird als Serialisierung bezeichnet. Das Wiedderherstellen von Objekten wird als Deserialisierung bezeichnet. Serialisierung Die Methode writeObject() schreibt die Objekte in einen Ausgabestrom der Klasse ObjectOuputStream. Dabei werden die die Zustände und Objektreferenzen rekursiv in den Ausgabestrom geschrieben. Statische Zustände werden nicht berücksichticht. Deserialisierung Mit der Methode readObject() wird ein Objekt aus einem ObjectInputStream zur Laufzeit aufgebaut. Anwendungsorientierte Programmierung Folie 169 10 Serialisierung Serialisierung (Schreiben von Objekten) OutputStream fos = null; try { fos = new FileOutputStream(dateiname); // Der Dateiname sollte die Endung .ser haben ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(object); } catch (IOException e) { System.err.println(e); } finally { try { fos.close(); } catch {Exception e} { e.printStackTrace(); } } Anwendungsorientierte Programmierung Folie 170 10 Serialisierung Fehlermeldungen (Exception) Allgemeine IOException NotSerializableException: Das Objekt ist nicht serialisierbar. InvalidClassException: Fehler in der Klassenstruktur Weiter Methoden von ObjectOutputStream void flush() throws IOException Schreibt noch gepufferte Daten void close() throws IOException Schließt den Datenstrom. Dieser Aufruf muss erfolgen bevor die Daten wieder gelesen werden. Anwendungsorientierte Programmierung Folie 171 10 Serialisierung Lesen von Objekten InputStream ios = null; try { fos = new FileOutputStream(dateiname); // Der Dateiname sollte die Endung .ser haben ObjectInputStream ois = new ObjectInputStream(ios); Class class = (Class) ios.readObject(object); } catch (IOException e) { System.err.println(e); } finally { try { ios.close(); } catch {Exception e} { e.printStackTrace(); } } Anwendungsorientierte Programmierung Folie 172 10 Serialisierung Eigene Klassen Serialisieren Die meisten vordefinierten Klassen (z. B. Collection) sind serialisierbar Damit eine eigen Klasse serialisierbar wird, muss sie die Schnittstelle Serializiable implementieren Hierdurch werden alle Attribute auch die der Oberklasse (außer statische) bei einer Serialisierung geschrieben. Bei Referenzen auf andere Objekte werden diese ebenfalls serialisiert. Zyklische Referenzen werden hierbei aufgelöst Anwendungsorientierte Programmierung Folie 173 10 Serialisierung Beispiel public class TheOne implements Serializable { private static final long serialVersionUID = 1L; private int val = 17; TheOther buddy; public TheOther getBuddy() { return buddy; } public void setBuddy(TheOther buddy) { this.buddy = buddy; } } public class TheOther implements Serializable{ private static final long serialVersionUID = 2L; private int val = 127; TheOne buddy; public TheOne getBuddy() { return buddy; } public void setBuddy(TheOne buddy) { this.buddy = buddy; } } Anwendungsorientierte Programmierung Folie 174 Serialisierung public class Main { public static void main(String[] args) { TheOne one = new TheOne(); TheOther other = new TheOther(); one.setBuddy(other); other.setBuddy(one); OutputStream fos = null; ObjectOutputStream oos = null; try { fos = new FileOutputStream("test.ser"); oos = new ObjectOutputStream(fos); oos.writeObject(one); } catch( IOException e ) { System.out.println(e); }; try { fos.close(); }catch( IOException e ) {} } Anwendungsorientierte Programmierung Folie 175 10 Serialisierung Ergibt ¬í sr serializepack.TheOne~tØEoÍÀ I valL buddyt Lserializepack/TheOther;xp sr serializepack.TheOther~tØEoÍÀ buddyt Lserializepack/TheOne;xp •q ~ I valL Die serialVersionUID (SUID) Jede serialisierbare Klasse erhält eine Versionsnummer. Diese berechnet sich aus den Attributen und Methoden der Klasse. Bei Änderungen an der Klasse ändert sich somit die SUID und das Objekt kann nicht mehr mit den Daten einer frühren Version geladen werden. Daher ist es sinnvoll die SUID selbst zu definieren: private static final long serialVersionUID = WertL; Der Wert ist beliebig, muss aber ein long (L) sein. Anwendungsorientierte Programmierung Folie 176 10 Serialisierung Gezielte Serialisierung Ohne weitere Maßnahmen werden alle Attributwerte, auch private, in den Datenstrom kopiert. Somit können interne Belegungen ausgelesen und manipuliert werden. Sollen bestimmte Attribute nicht serialisiert (in den Datenstrom kopiert) werden. So sind diese mit dem durch das Schlüsselwort transient zu kennzeichnen. Beispiel public class Private implements Serializable { private static final long serialVersionUID = 1L; private int val = 17; transient String passwort = "geheim"; } Anwendungsorientierte Programmierung Folie 177 10 Serialisierung Eine weitere Möglichkeit ist die Vorgabe von serialPersistentFields. Diese ist vom Typ ObjectStreamField[]. public class Private implements Serializable { private static final long serialVersionUID = 1L; private static ObjectStreamField[] serialPersistentFields = new ObjectStreamField[] { new ObjectStreamField("val", Integer.class), new ObjectStreamField("benutzername", String.class), } private int val = 17; transient String benutzername = "nicht geheim"; transient String passwort = "geheim"; } Anwendungsorientierte Programmierung Folie 178 10 Serialisierung Die Art der Serialisierung kann auch vorgegeben werden. Hierzu muss/kann eine Klasse die Methoden: private synchronized void writeObject(ObjectOutputStream oos) Schreiben von Werten private synchronized void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException Lesen von Werten implementieren. Diese werden dann vom Serialisierer aufgerufen. Soll dennoch der Standartserialisierer verwendet werden so können die Methoden private final void defaultWriteObject() throws IOException private final void defaultReadObject() throws IOException, ClassNotFoundException aufgerufen werden Anwendungsorientierte Programmierung Folie 179 10 Serialisierung Beispiel public class Private implements Serializable { private static final long serialVersionUID = 1L; private int val = 17; transient String passwort = "bleibt geheim"; private void writeObject(ObjectOutputStream oos) throws IOException, ClassNotFoundException { oos.defaultWriteObject(); // Schreibt val } private void readObject(ObjectInputStream ios) throws IOException, ClassNotFoundException { ios.defaultWriteObject(); // liest val passwort = "bleibt geheim"; // muss eigentlich in einem tryBlock stehen } } Anwendungsorientierte Programmierung Folie 180 11 Grafikprogrammierung Erste Versuche Wir wollen hier auf ein JPanel (javax.swing.JPanel) zeichnen. Hierfür wird auch die Klasse Graphics (java.awt.Graphics) aus awt benötigt. Wird ein JPanel neu gezeichnet so wird die Methode paint aufgerufen. Es sollte allerdings nicht die Methode sondern die umfassendere paintComponent überschrieben werden. protected void paintComponent(Graphics g) { // Zeichenbefehle } Anwendungsorientierte Programmierung Folie 181 11 Grafikprogrammierung import java.awt.Graphics; import javax.swing.*; public class DrawPanel extends JPanel { protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawLine(10, 10, 100, 50); } } public class Main { public static void main(String[] args) { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setSize(100, 100); f.add(new DrawPanel()); f.setVisible(true); } } Anwendungsorientierte Programmierung Folie 182 11 Grafikprogrammierung Ein Komponente kann durch Aufruf von repaint() zum Neuzeichnen aufgefordert werden void repaint() void repaint(long tm) Neuzeichnen nach tm Millisekunden void repaint(int x, int y, int width, int height) Neuzeichnen im angegeben Bereich void repaint(long tm, int x, int y, int width, int height) alles zusammen Anwendungsorientierte Programmierung Folie 183 11 Grafikprogrammierung Erweiterung der Zeichenfähigkeiten Die Klasse Graphics wurde in der JDK 1.2 eingeführt. Inzwischen wurde die Graphik erweitert. Die Methoden befinden sich in der Unterklasse Graphics2D von Graphics. Daher sollte diese verwendet werden protected void paintComponent(Graphics g) { Graphics2D g2D = (Graphics2D)g; // Type-Cast … } Anwendungsorientierte Programmierung Folie 184 11 Grafikprogrammierung Der Nullpunkt Einfache Zeichenroutinen abstract void drawLine(int xa, int ya, int xe, int ye) zeichnet eine Linie zwischen den Punkten (xa, ya) und (xe, ye). Anwendungsorientierte Programmierung Folie 185 11 Grafikprogrammierung Grundgerüst für eine Zeichenfläche public class PaintPanel extends JPanel { public PaintPanel() { this.setBackground(Color.WHITE); // Setzen des Hintergrundes } // Die eigentliche Methode zum Zeichnen @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D)g; g2d.setColor(Color.BLACK); // Setzen der Zeichenfarbe // Zeichenroutinen } } Anwendungsorientierte Programmierung Folie 186 11 Grafikprogrammierung Einbinden der Zeichenfläche public class CanvasGUI extends JFrame { privatePaintPanel canvas = new PaintPanel(); public CanvasGUI() { Container p = this.getContentPane(); p.add(canvas); } } Anwendungsorientierte Programmierung Folie 187 11 Grafikprogrammierung Rechtecke void drawRect(int x, int y, int width, int height) Zeichnet ein Rechteck. Das Rechteck ist width+1 Pixel breit und height+1Pixel hoch. void fillRect(int x, int y, int width, int height) Zeichnet ein gefülltes Rechteck. Das Rechteck ist width Pixel breit und height Pixel hoch. void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) Zeichnet ein Rechteck mit gerundeten Ecken. Das Rechteck ist width+1 Pixel breit und height+1Pixel hoch. Durch arcWidth und arcHeight wird der Durchmesser der Kreisbögen angegeben void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) gefülltes Rechteck mit runden Ecken. Anwendungsorientierte Programmierung Folie 188 11 Grafikprogrammierung Kreise, Ellipsen, Bögen (x, y) drawOval(int x, int y, int width, int height) zeichnet eine Ellipse innerhalb eines gedachten Rechtecks mit der Breite widthund der Höhe height fillOval(int x, int y, int width, int height) wie oben aber gefüllt height width drawArc(int x, int y, int w, int h, int start, int winkel) zeichnet eine Bogen winkel fillArc(…) gefüllt, sonst wie oben 0° start (negativ) Anwendungsorientierte Programmierung Folie 189 11 Grafikprogrammierung Text Ein Fond erzeugen Font(String fontname, int style, int size) style: Font.PLAIN, Font.BOLD, Font.ITALIC oder zusammengesetzt Font.BOLD | Font.ITALIC size: Größe in Pixeln Bsp: Font f = new Font("Arial", Font.PLAIN, 14) Font getFont(), setFont(Font f) liefert bzw. setzt den Font in der aktuellen Graphikumgebung Mit deriveFont(attribut) kann aus einem bestehenden Font ein Neuer mit anderen Attributen (Größe, Stil ) erzeugt werden. Die Größe muss als float angegeben werden. Bsp Font f20 = f.deriveFont(20f) Anwendungsorientierte Programmierung Folie 190 11 Grafikprogrammierung Das Zeichnen von Text erfolgt durch void drawString(String s, int x, int y) Bsp. drawString("String", 50, 50); 50 In der Klasse FontMetrics sind verschiedene Information über den aktuellen Font gespeichert Bsp.: (g ist vom Typ Graphics) FontMetrics fm = g.getFontMetrics() FontMetrics fm = g.getFontMetrics(Font) Die Breite des gezeichneten Strings kann durch int drawWidth = fm.stringWidth("String"); ermittelt werden Anwendungsorientierte Programmierung 50 String Folie 191 11 Grafikprogrammierung Festlegung der Linieart Anwendungsorientierte Programmierung Folie 192 Viel Spaß bei der weiteren Erkundung von Java Anwendungsorientierte Programmierung