Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Anwendungsorientierte Programmierung I

Ähnliche Präsentationen


Präsentation zum Thema: "Anwendungsorientierte Programmierung I"—  Präsentation transkript:

1 Anwendungsorientierte Programmierung I
Das d Notizen Anwendungsorientierte Programmierung I Heinrich Krämer Hochschule für Technik, Wirtschaft und Kultur Leipzig (FH) Fachbereich Informatik, Mathematik und Naturwissenschaften

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

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.

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-Down-Methode 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. Thomas Watson Sr.

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 auf Vielfache untersucht werden Teilproblem: Streichen der Vielfachen aller Primzahlen im Bereich 2.. Teilproblem: Ausgabe aller nicht gestrichenen Zahlen

6 1. Einleitung 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) 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

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

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.

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;

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.

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

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

13 2.2 Primitive Datentypen Typ Wertebereich Größe Format
Ganzzahlen (Numerisch) byte 8 Bit Zweierkomplement short 16 Bit int 32 Bit long 64 Bit Gleitkommazahlen (Numerisch) float 1, E-45..3, E+38 IEEE 754 double Weitere Datentypen boolean true oder false nicht def. char Unicode (Numerisch) 16-Bit-Unicode

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) (Oktal ) 0xFFFF_FFFF (Hexadezimal -110) long-Literale (es muss immer ein l angehängt werden) 1234L (Dezimal) 0b11L (Dual 310) L (Oktal ) 0xFFFF_FFFFL (Hexadezimal ) float-Literale (es muss immer ein f angehängt werden) 1.0f 2F 1e-1f E+5f E1f double-Literale D 1e-1d 4.0E E1

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 ProjectProperties die Codierung auf UTF-8 umgestellt werden

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 Beispiel double x = Double.valueOf("3.1415");

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

18 2.3 Operatoren Arithmetische Operatoren Unitäre Operatoren Typ
Beschreibung Rang + Numerisch Vorzeichen 1 - ++ Inkrement (+1) -- Dekrement (-1) Binäre Operatoren Typ Beschreibung Rang + Numerisch Addition 3 - Subtraktion * Multiplikation 2 / Division % Modulo (Rest)

19 2.3 Operatoren Vergleichsoperatoren Typ Beschreibung Rang <
Numerisch, char kleiner 5 > größer <= kleiner oder gleich >= größer oder gleich == ungleich 6 != gleich logische Operatoren (Datentyp boolean) ! boolean Negation 1 && UND (Kurzauswertung) 10 || ODER (Kurzauswertung) 11 ^ Antivalenz 8 & UND 7 | ODER 9

20 2.3 Operatoren Bitweise Operatoren Typ Beschreibung Rang ~ Numerisch
bitweises Komplement 1 & bitweises UND 7 | bitweises ODER 9 ^ bitweise Antivalenz 8 << Schieben links 4 >> log. Schieben rechts >>> arith. Schieben rechts weitere Operatoren (typ) alle Typumwandlung new später instanceof 5 exp ? exp : exp Auswahl 12

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 Beispiel x = x * 10.0 ist identisch zu x *= 10.0 14 -= *= /= %= <<= >>= >>>= &= |= ^=

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 / * 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

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 short int long float double byte X (X)

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;

25 2.5 Anweisungen BlockAnweisung: //heute Block AusdrucksAnweisung
IfAnweisung WhileAnweisung DoAnweisung Block: { {BlockAnweisung } } Blöcke dienen der Zusammenfassung von mehreren Anweisungen zu einer.

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 = ; y = r = 2.0 * x; a++; --a; b = ++a * 10;

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

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.

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"); else { System.out.println(k); i /= k; }

30 2.5 Anweisungen WhileAnweisung: (Schleife) while ( Ausdruck )
Eine Schleife dient zur mehrfachen Ausführung einer Anweisung. Beispiele: int a = 10; while (a >= 0) a--; while (a >= 0) while (a >= 0){ a--; a--; System.out.println(a); System.out.println(a); //wahrscheinlich fehlerhaft } // Block

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 do n = tastatur.nextInt(); n = tastatur.nextInt(); while (n != 0); System.out.println(n); while (n != 0); // Fehlerhaft

32 2.5 Anweisungen ForAnweisung: for ([ForInit];[Ausdruck];[ForUpdate])
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;

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.

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.

35 2.5 Anweisungen SwitchAnweisung: switch ( Ausdruck ) {
{ case CaseMarke : { Anweisung } } [ default: ] 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.

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 default: // Anweisungen falls kein Fall zutrifft }

37 2.5 Anweisungen Regeln für switchAnweisungen
Die Anweisungsfolge für jeden Fall (case) oder Fälle muss durch eine breakAnweisung (break) abgeschlossen werden. Grundsätzlich sollte jede caseAnweisung ein default enthalten. Hier handelt es sich meist um einen Entwurfsfehler, daher sollte immer eine Fehlermeldung ausgegeben werden.

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.

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(); } System.out.print(i+"ter Messwert = " + messwerte[i]);

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]

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.

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.

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(); }

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

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

46 3.3 Klassen Attributdeklaration: [Modifizierer] Variablendeklaration
Methodendeklaration: [Modifizierer] Rückgabetyp Methodenname (Parameter) { { Anweisungen } } Rückgabetyp: Typ void

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

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();

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.

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.

51 4 Unterprogramme Die returnAnweisung return; //1 return Ausdruck; //2
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. 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.

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

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.

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; } Aufruf von max double x = 18.1; double y = 5.9; 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) Umgebung von max a b 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 a 59.0 b 1.81

55 4.1 Parameterübergabe Benutzerdefinierte Datentypen (Felder oder Klassen) Benutzerdefinierte Datentypen sind grundsätzlich Referenzen. Leider wird in Java der eigentliche Mechanismus verdeckt. Zylinder z = new Zylinder(); 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 radius hoehe Referenzvariable z Adresse Speicher für Zylinder k Adresse von z

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) }

57 5 Verwendung vordefinierter Klassen
Ableitung von Klassen Oberklasse (Basisklasse) Fahrzeug Sitzplätze Unterklasse (abgeleitete Klasse) erben: Sitzpläze Spezialisierung Kutsche Anzahl Pferde Fahrrad Kraftfahrzeug Motorleistung void kraftfahrstrasse(Kraftfahrzeug f) { …} PKW ferrari = new PKW(); Fahrrad peugeot = new Fahrrad(); kraftfahrstrasse(ferrari); // legal da Kraftfahrzeug kraftfahrstrasse(peugeot); // kein Kraftfahrzeug PKW LKW hat Sitzplätze Motorleistung

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

59 5.1 Fehlerbehandlung TryCatchBlock try { { Anweisungen }
} {catch ( ExceptionTyp Name){ }} [finally { } ]

60 5.1 Fehlerbehandlung Beispiel try {
// Anweisungen die eine allgemeine IOException, eine // FilenotFoundException oder eine NumberFormatException // auslösen } catch (IOException e) { if (e isinstanceof FileNotFoundExcception) { // Behandlung von dieser Ausnahme } else { // allgemeiner Eingabefehler } } catch (NumberFormatException e) { // Behandlung dieser Ausnahme } finally { // wird immer ausgeführrt

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 } Auslösen von Exceptions public static void setAge( int a) throws IllegalArgumentException { if (a <= 0) throw new IllegalArgumentException("Age must be > 0!"); age = a; zeichnen.setText(

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

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

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

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();

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;

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

68 Objektorientierte Programmierung

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.

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.

71 7.1 Schreiben eigener Klassen
[Modifizierer] class Klassennamen [extends Klassenname]{ { Klassenelemente } } Klassenelemente: Attributdeklaration Methodendeklaration Unterklassen Modifizierer public protected private abstract static final strictfp

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.

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.

74 7.1 Schreiben eigener Klassen
Beispiel Bsp obj = obj.read() // zulässig obj.nr = 10; // unzulässig obj.setNr(10); // zulässig obj.index = 1; //unzulässig // index ist nicht zugreifbar obj.print(); // ok Bsp.print(); // unzulässig int i = obj.foo() // unzuässig, da // private int i = obj.nr; // s.o. public class Bsp { private int index; private int nr; public void setNr(int nrPar) { nr = nrPar; } public int getNr() { return nr; public void print() { …} private int foo() {…} public Bsp read() {…}

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 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

76 7.1 Schreiben eigener Klassen

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

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.

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 Standard-Konstruktor mehr ein. Wird dieser benötigt, so muss er manuell hinzugefügt werden.

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;

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; 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.

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.

83 7.2 Ableiten von Klassen Es kann beliebig viele Hierarchiestufen geben
Jede abgeleitete Klasse (Unterklasse) ist auch vom Typ der Oberklasse A a = new DCA(); mit instanceof kann der Typ geprüft werden a instanceof A // true a instanceof CA // true a instanceof DCA // true a instanceof ECA // false a instanceof BA // false class A class BA extends A class CA extends A class DCA extends CA class ECA extends CA In Java sind alle Klassen vom Typ Object

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();

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.

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

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 Lösung: Direktive @Override vor der Methode einfügen

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

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.

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.

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; }

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

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

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

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

96 7.6 Schnittstellen (Interfaces)
Beispiele public interface Position { void setPoint(double x, double y); } public interface GeoObjekt { double flaeche(); double umfang();

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

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();

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

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;

101 7.7 Innere Klassen class Aussen { Innen inner; … class Innen { int y;
} Deklaration: Aussen.Innen abc; Zugrifff: Aussen inst; inst.inner.y = 17;

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

103 7.8 Modellierung der Daten
Unterschiedliche Arten von Datenstrukturen Beispiel: Graph Datenstrukturen zur Verwaltung: Liste von Knoten Liste von Kanten Datenstrukturen für die Information Knoten Index, Farbe Vorgänger, Nachfolger (Nachbar) Kanten Von, Nach bzw. K1, K2 1 6 2 5 3 4

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

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 { … } …

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 { public class Usambaraveilchen extends Blumen {…} …

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();

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); …

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

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); …

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"); }

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

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") {

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

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

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 String toString() { return ("(" + l.toString + "," + r.toString +")");

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

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)

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) {…} void methode(Paar<? super Comparable> p) {…}

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

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 falls this < to == 0 falls this == to > 0 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

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

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

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

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.

126 8 Java-Collections-Framework
Die Ableitungsstruktur weiterer Interfaces Interface Iterable liefert Iterator Interface Collection Interface: Queue Schlangen/FIFO Interface: Set Mengen Interface: List Interface für Listen/Sequenzen Interface: Deque zweiseitig Map ist eine weitere Schnittstelle, die zur Verwaltung von Assoziationen (Schlüssel,Wert) verwendet wird Interface: ArrayList Interface: LinkedList

127 8 Java-Collections-Framework
Implementierungen (Klassen) List (Listen) ArrayList Liste als Feld LinkedList Doppelt verkettete Liste Set (Mengen) HashSet implementiert Menge durch schnelle Hash-Verfahren TreeSet Elemente sind sortiert, implementiert Menge als Baum LinkedHashSet sortiert, schnelles Hash-Verfahren Map HashMap Assoziationen durch Hash-Verfahren TreeMap Assoziationen durch Baum, sortiert LinkedHashMap Hash-Verfahren, sortiert WeekHashMap Elemente können entfernt werden Queue s.o. ArrayBlockingQueue Blockierenden Warteschlange PriorityQueue Prioritätswarteschlange

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

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

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.

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

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

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

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.

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

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]

137 8 Java-Collections-Framework
Verallgemeinerte ForSchleife alle Collections-Klassen können auch mit einem impliziten Iterator in der foreach-Schleife benutzt werden Bsp.: List<String> liste = new LinkedList<String>() . . . for ( String s : liste) System.out.println(s);

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

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.

140 9 Graphische Benutzeroberflächen
JFrame Title (setTitle()) Decorated(setDecorated(true/false) Größe (setSize(b, h)) Ort (setLocation(x, y) ContentPane

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

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

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

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

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)

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-Menus (JPopUpMenu) Tabellen (JTable und TableModel) Baumdarstellungen (JTree und TreeModel)

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

148 9.1 Erstellen von GUIs (Graphical User Interface)
Manuelle Platzierung der Elemente 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); } 10, 10 20 80

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

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

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.)

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

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"); }

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 } }

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"); } });

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.

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"); flaeche.add(btn); pack();

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

159 9.3 Graphische Benutzeroberflächen
Ein Beispiel Borderlayout NORTH CENTER EAST WEST SOUTH Jpanel BoxLayout, Y_AXIS Jpanel FlowLayout

160 9.3 Ereignisbehandlung Die Ereignisquellen und ihre Listener (awt)
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

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.

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

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); }

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);

165 9.3 Ereignisbehandlung Die Ereignisse einer Komponente (JComponent)
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

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

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

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.

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(); } }

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.

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(); } }

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

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; }

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 ) {} }

175 10 Serialisierung Ergibt
¬í sr serializepack.TheOne~tØEoÍÀ I valL buddyt Lserializepack/TheOther;xp sr serializepack.TheOther~tØEoÍÀ I valL buddyt Lserializepack/TheOne;xp q ~  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.

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"; }

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";

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() aufgerufen werden

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) ios.defaultWriteObject(); // liest val passwort = "bleibt geheim"; // muss eigentlich in einem tryBlock stehen

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 }

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);

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

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 }

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).

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 protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D)g; g2d.setColor(Color.BLACK); // Setzen der Zeichenfarbe // Zeichenroutinen

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); }

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, gefülltes Rechteck mit runden Ecken.

188 11 Grafikprogrammierung
Kreise, Ellipsen, Bögen 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 drawArc(int x, int y, int w, int h, int start, int winkel) zeichnet eine Bogen fillArc(…) gefüllt, sonst wie oben (x, y) height width winkel start (negativ)

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)

190 11 Grafikprogrammierung
Das Zeichnen von Text erfolgt durch void drawString(String s, int x, int y) Bsp. drawString("String", 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 50 50 String

191 11 Grafikprogrammierung
Festlegung der Linieart

192 Viel Spaß bei der weiteren Erkundung von Java


Herunterladen ppt "Anwendungsorientierte Programmierung I"

Ähnliche Präsentationen


Google-Anzeigen