int

Werbung
Programmiersprache Java
Objektorientierte Programmierung II
Peter Becker
FH Bonn-Rhein-Sieg
Fachbereich Informatik
[email protected]
Vorlesung Sommersemester 2008
Vorbemerkungen
Allgemeines zur Vorlesung
• Homepage zur Vorlesung:
http://www2.inf.fh-rhein-sieg.de/˜pbecke2m/progjava/
• Die Vorlesung wird folienbasiert gehalten.
• Die Folien zur Vorlesung (Skript) stehen auf der Homepage vor der Vorlesung zur
Verfügung.
• Format: PDF, ein- und vierseitig
• Empfehlung: Bringen Sie die ausgedruckten Folien mit in die Vorlesung und versehen Sie diese dort mit schriftlichen Bemerkungen.
• Benutzen Sie zum Drucken bitte die vierseitige Version des Skriptes.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
1
Vorbemerkungen
Organisation
•
•
•
•
Vorlesung V2, Dienstag 11:30 – 13:00 Uhr
Bitte beachten Sie die Gruppeneinteilung für die Übungen!
Für die Übungen benutzen wir Linux!
Die wichtigsten Dinge für diese Veranstaltung:
1. Üben!
2. Üben!
3. Üben!
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
2
Vorbemerkungen
Voraussetzungen und Lernziele
Voraussetzungen:
• Beherrschung des Stoffes “Einführung in die Programmierung” bzw. “Objektorientierte Programmierung I”
insbesondere: algorithmische Elemente, abstrakte Datentypen, Rekursion, Java
Grundlagen (einfache Datentypen, Kontrollstrukturen, Arrays)
Lernziele:
Programmieren lernen
Kennen der Konzepte der objektorientierten Programmierung
Kennen der Sprachkonzepte von Java
Selbständig Programme in Java zu anwendungsorientierten Problemstellungen
entwicklen können
• Beherrschung einer objektorientierten Programmiersprache
•
•
•
•
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
3
Vorbemerkungen
Prüfung
• Modulzuordnung:
Computer Science: GPS, 2. Semester
Business Information Systems: GINF, 2. Semester
• Schriftliche Prüfung in Form einer zweistündigen Klausur
• Art der Klausur: Wissensfragen und Programmierung (auf Papier)
• Hilfsmittel: keine
• 7 Credits
• keine weiteren Zulassungsvoraussetzungen?
• Bonuspunkte?
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
4
Vorbemerkungen
Inhalt
1. Referenzdatentypen, Felder
2. Benutzung von Klassen
3. Konstruktion von Klassen
4. Vererbung
5. Abstrakte Klassen
6. Ausnahmebehandlung (Exceptions)
7. Schnittstellen
8. parametrisierbare Klassen (Generics)
9. Pakete
10. Java Klassenbibliotheken
11. Threads
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
5
Vorbemerkungen
Literatur
D. Ratz, J. Scheffler, D. Seese
Grundkurs Programmieren in Java
Band 1: Der Einstieg in Programmierung und Objektorientierung
Hanser
2004
• Standardwerk für diese Veranstaltung
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
6
Vorbemerkungen
J. Goll, C. Weiß, F. Müller
Java als erste Programmiersprache
Teuber
2001
• Früheres Standardwerk für diese Veranstaltung
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
7
Vorbemerkungen
C. Ullenboom
Java ist auch eine Insel
Galileo Press
2005
• Sehr umfangreich
• Behandelt
weiterführende
Themen
(z.B.
Datenbank- und Netzwerkprogrammierung,
XML, Grafische Oberflächen).
• Geht weit über die Inhalte dieser Veranstaltung
hinaus.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
8
Vorbemerkungen
Oliver Böhm
Java Software Engineering unter Linux
SuSE Press
2002
• Vermittelt keine Grundlagen,
• enthält dafür alles, was man zur professionellen Softwareentwicklung mit Java unter Linux
benötigt.
• Ein Buch für das gesamte Studium.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
9
1. Felder und Strings
Eigenschaften von Referenzdatentypen
1. Referenzdatentypen: Felder und Strings
• Referenzdatentypen sind Konstrukte, mit deren Hilfe wir aus einfachen Datentypen
neue “eigene” Typen erzeugen können.
• In Java gibt es prinzipiell zwei Arten von Referenzdatentypen: Felder und Klassen.
• In diesem Kapitel lernen wir den Umgang mit Feldern und die Benutzung der Klassen String und StringBuffer.
• Die Nutzung von Klassen ist Thema des nächsten Kapitels.
• Die Definition eigener Klassen ist Thema des übernächsten Kapitels.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
10
1. Felder und Strings
Eigenschaften von Referenzdatentypen
Referenz- vs. einfache Datentypen
• einfacher Datentyp: Eine Speicherzelle, die mit einer Variablen assoziiert ist,
enthält den Wert der Variablen (direkter Zugriff).
• Referenztyp: Eine Speicherzelle, die mit einer Variablen assoziiert ist, enthält eine
Referenz (Verweis, Zeiger) auf eine andere Speicherzelle, die den Wert enthält
(indirekter Zugriff).
symbolische Adresse
b
Adresse im Speicher
...
Inhalt
...
Typ
96
4711
int
r
...
104
...
124
...
...
124
...
...
Referenz
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
11
1. Felder und Strings
Eigenschaften von Referenzdatentypen
• Im Unterschied zum einfachen Datentyp wird der Wert 124 der Variablen r nicht als
numerischer Wert interpretiert, sondern als Adresse für eine andere Speicherzelle.
Dort findet sich der “eigentliche” Wert bzw. unser “eigentliches” Objekt.
• Mit der Literalkonstanten null repräsentieren wir eine Referenz, die auf nichts (in
das Nirgendwo) verweist.
Wenn die Variable r von einem Referenztyp ist, dann sind
r = null;
...
if ( r == null )
...
gültige Anweisungen.
• Grafische Notation für Variablen:
b
4711
r
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
12
1. Felder und Strings
Einfache Datentypen
Rückblick: Einfache Datentypen (1)
• Ganzzahlige Datentypen
long int short byte
Repräsentation: Zweierkomplement
• Gleitkommatypen
double float
Repräsentation: 32 bzw. 64 Bit im IEEE 754 Standard
• char
Repräsentation: als vorzeichenloser 16-Bit Integerwert
• boolean
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
13
1. Felder und Strings
Einfache Datentypen
Rückblick: Einfache Datentypen (2)
Zu einem einfachen Datentyp gehört
• sein Wertebereich,
• sein lexikalischer Bereich (Literale) und
• die zur Verfügung stehenden Operationen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
14
1. Felder und Strings
Einfache Datentypen
Einfache Datentypen: Implizite und explizite Typumwandlung
• Wir wollen die Addition
92233720366854775000L + 807
durchführen. Der Plus-Operator ist aber nur für Werte des gleichen Typs definiert.
Was tun?
• Der Java-Compiler erkennt, daß der Datentyp zur linken Zahl einen Wertebereich
hat, der den der rechten Zahl umfasst. So wird die 807 vom Compiler in eine
automatisch long-Zahl umgewandelt.
☞ implizite Typkonvertierung (implicite typecast)
• Implizite Typkonvertierungen treten immer dann auf, wenn ein kleinerer Zahlenbereich in einen größeren Zahlenbereich abgebildet wird.
byte → short → int → long
char → int
float → double
• Ganzzahlige Datentypen können auch implizit in Gleitkommatypen umgewandelt
werden, obwohl dabei Rundungsfehler auftreten können.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
15
1. Felder und Strings
Einfache Datentypen
• Die folgende Anweisung dagegen liefert einen Fehler beim Compilieren:
int i = 3.0;
Grund: 3.0 ist eine double-Zahl. Bei einer Umwandlung nach int geht eventuell
Information verloren.
• Stattdessen könnten wir eine explizite Typkonvertierung (explicite Typecast)
durchführen. Hierzu schreibt man den Zieldatentyp in Klammern vor die entsprechende Zahl oder Ausdruck.
(int) 3.14
Hier würde der Compiler die Nachkommastellen abschneiden.
• Eine Umwandlung von boolean in einen anderen Datentyp ist nicht möglich.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
16
1. Felder und Strings
Eindimensionale Felder
Felder
• Felder (Arrays) gestatten es, mehrere Variablen durch einen gemeinsamen Namen
anzusprechen und lediglich durch einen Index zu unterscheiden.
• Alle diese indizierten Variablen haben dabei den gleichen Typ (Komponententyp,
Basistyp).
• Die Variablen selbst werden als Komponenten des Feldes bezeichnet.
• Der Index zum Ansprechen der Komponenten ist vom Typ int. Hierbei sind nur
nichtnegative Werte erlaubt.
• Wir können uns vorstellen, daß die Komponenten eines Feldes aufeinanderfolgend
im Speicher des Rechners abgelegt sind.
• Der Index für eine Komponente ergibt sich dabei aus der Position innerhalb des
Feldes, von Null aufwärts gezählt.
• Beispiel:
– Repräsentation eines Vektors des IRn: Feld mit double als Komponententyp
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
17
1. Felder und Strings
Eindimensionale Felder
Deklaration von Feldern
Syntax:
Komponententyp[] Variablenname;
Beispiele:
int[]
zahlenfolge;
double[] vektor;
• Die eckigen Klammern machen deutlich, daß die Variable ein Feld referenziert, mit
dem Typ links von [] als Komponententyp.
• Als Komponententyp sind nicht nur einfache Datentypen, sondern auch Referenztypen erlaubt.
String[] wortliste;
• Insbesondere sind auch Feldtypen als Komponententyp erlaubt (hierzu später
mehr).
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
18
1. Felder und Strings
Eindimensionale Felder
Erzeugung von Feldern
☞ Die Deklaration einer Feld-Variablen erzeugt kein Feld!
• Nach der Deklaration existiert eine Variable, die eine Referenz auf ein Feld als
Wert aufnehmen, kann.
• Das eigentliche Feld existiert aber noch nicht.
Syntax zur Erzeugung von Feldern:
Variablenname = new Komponententyp [ Feldlänge ];
Beispiele:
zahlenfolge = new int[20];
vektor
= new double[3];
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
19
1. Felder und Strings
Eindimensionale Felder
Deklaration und Erzeugung können auch zusammen erfolgen. Beispiele:
int[]
zahlenfolge = new int[20];
double[] vektor = new double[3];
Bitte beachten Sie:
☞ Die Größe eines Feldes ist nicht Bestandteil des Typs. Sie wird erst bei der Erzeugung des Feldes festgelegt.
☞ Die Feldlänge kann durch einen Ausdruck angegeben werden.
☞ Einer Feld-Variable können jederzeit andere Felder gleichen Typs zugewiesen werden.
double[] vektor = new double[3];
double[] vektor2 = new double[7];
vektor = new double[3];
vektor = new double[5];
vektor = vektor2;
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
20
1. Felder und Strings
Eindimensionale Felder
Komponentenzugriff und -initialisierung
double[] vektor = new double[3];
Welchen Wert haben die Feldkomponenten nach der Erzeugung?
Dies ist für jeden möglichen Komponententyp festgelegt:
•
•
•
•
•
ganzzahlige Typen: 0
char: ’\0’
double bzw. float: 0.0 bzw. 0.0f
boolean: false
Referenztyp: null
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
21
1. Felder und Strings
Eindimensionale Felder
Syntax für die Wertzuweisung an eine Komponente:
Variablenname[Index] = Wert;
Beispiel:
vektor[0] = 1.0; vektor[1] = 2.0; vektor[2] = -1.0;
• Index muß ein Ausdruck sein, der einen int-Wert liefert.
• Der Wert für Index muß zwischen 0 und Feldlänge-1 liegen.
• Wert kann natürlich ein beliebiger Ausdruck passend zum Komponententyp sein.
int[] quadratFolge = new int[100];
for (int i=0 ; i<100 ; i++ )
quadratFolge[i] = i*i;
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
22
1. Felder und Strings
Eindimensionale Felder
Syntax für den Zugriff auf den Wert einer Komponente (als Ausdruck):
Variablenname[Index]
Beispiel:
double summe = 0.0;
for (int i=0 ; i<3 ; i++ ) {
System.out.println( "vektor[" + i + "] = " + vektor[i] );
summe = summe + vektor[i] * vektor[i];
}
System.out.println("Laenge des Vektors: " + Math.sqrt( summe ));
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
23
1. Felder und Strings
Eindimensionale Felder
• Statt Erzeugung mit new und anschließender Initialisierung durch Wertzuweisungen ist auch eine verkürzte Schreibweise möglich.
• Beispiele:
int[]
lottozahlen = { 6, 11, 19, 21, 30, 40 };
double[] vektor = { 1.0, 2.0, -1.0 };
String[] wortliste = { "ganz", "viele", "Wörter" };
• Die geklammerten Ausdrücke heißen Feld-Initialisierer (array initializer).
• Nur Literale oder Konstanten dürfen als Wert in einem Feld-Initialisierer auftreten.
• Diese Schreibweise ist nur in Verbindung mit einer Deklaration erlaubt, nicht für
eine gewöhnliche Zuweisung.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
24
1. Felder und Strings
Eindimensionale Felder
Ermittlung der Länge von Feldern
• Bei der Erstellung eines Feldes wird dessen Länge in einem zusätzlichem Element
vom Typ int abgespeichert.
• Auf dieses Element kann mit
Variablenname.length
zugegriffen werden.
• Beispiel:
double[] vektor = { 1.0, 2.0, -1.0 };
for (int i=0 ; i<vektor.length ; i++ )
System.out.println( "vektor[" + i + "] = " + vektor[i] );
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
25
1. Felder und Strings
Eindimensionale Felder
Kopieren und Vergleichen von Referenzen
double[] v = { 1.0, 3.0, 5.0, 10.0 };
double[] q = v;
for ( int i=0 ; i<q.length ; i++ )
q[i] = q[i]*q[i];
for ( int i=0 ; i<q.length ; i++ )
System.out.println( "Das Quadrat von " + v[i] + " ist " + q[i] );
Was wird ausgegeben und warum?
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
26
1. Felder und Strings
Eindimensionale Felder
• Die Zuweisung q = v; führt zu einer sogenannten Referenzkopie.
• Es wird keine Kopie des Feldes angelegt, sondern q erhält die Referenz, die in v
hinterlegt ist.
• Wirkung: q und v verweisen auf das gleiche Feld.
v
1.0
3.0
5.0
10.0
q
Für die Herstellung einer “echten Kopie” haben wir die folgenden Möglichkeiten:
1. Wir benutzen eine Schleife:
double[] v2 = new double[ v.length ];
for ( int i=0 ; i<v.length ; i++ )
v2[i] = v[i];
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
27
1. Felder und Strings
Eindimensionale Felder
2. Nutzung der Methode System.arraycopy:
System.arraycopy( Quelle, QuelleStartIndex,
Ziel, ZielStartIndex,
Anzahl );
Hierbei ist:
• Quelle: Feld, von dem kopiert werden soll
• QuelleStartIndex: Index, ab der Quelle übertragen werden soll
• Ziel: Feld, in das kopiert werden soll
• ZielStartIndex: Index, ab dem die Eintragungen erfolgen sollen
• Anzahl: Anzahl der zu kopierenden Komponenten
3. Nutzung der vordefinierten Methode clone. Hierzu später mehr.
☞ Alle diese Möglichkeiten legen eine sogenannte flache Kopie an.
☞ D.h. für die Komponenten selbst wird die übliche Zuweisung durchgeführt.
☞ Dies kann problematisch sein, wenn der Komponententyp selbst eine Referenzdatentyp ist (Referenzkopie).
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
28
1. Felder und Strings
Eindimensionale Felder
• int[] feld1 = { 1, 2, 3 };
int[] feld2 = { 1, 2, 3 };
• Der Ausdruck feld1 == feld2 liefert false!
• Begründung: Bei Referenzdatentypen bedeutet == nicht, daß die Inhalte der referenzierten Felder (oder Objekte) verglichen werden.
• Stattdessen wird geprüft, ob die Referenzen die gleiche Speicherstelle adressieren.
feld1
1
2
3
feld2
1
2
3
• Wie vergleicht man dann die Inhalte von Feldern?
☞ Ausprogrammieren
• Achtung: Der Komponententyp kann wieder ein Referenztyp sein!
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
29
1. Felder und Strings
Mehrdimensionale Felder
Mehrdimensionale Felder
Mehrdimensionale Felder sind vom Prinzip her leicht zu definieren: Der Komponententyp ist selbst ein Feld.
Beispiele:
double[][] matrix;
int[][]
folgeVonFolgen;
String[][] listeVonStringListen;
Sollen alle “inneren” Felder die gleiche Länge aufweisen, können wir wiederum den
new-Operator in einfacher Weise verwenden:
matrix = new double[3][4];
folgeVonFolgen = new int[3][50];
listeVonStringListen = new String[5][30];
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
30
1. Felder und Strings
Mehrdimensionale Felder
Beispiele für “innere” und “äußere” Feldlängen:
• matrix.length liefert 3.
• matrix[0].length liefert 4.
• matrix[2].length liefert ebenfalls 4.
Die “inneren” Felder können eine unterschiedliche Länge aufweisen.
int[][] folgeVonFolgen = new int[3][];
for ( int i=0 ; i<folgeVonFolgen.length ; i++ )
folgeVonFolgen[i] = new int[10*(i+1)];
• folgeVonFolgen.length liefert 3.
• folgeVonFolgen[0].length liefert 10.
• folgeVonFolgen[2].length liefert 30.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
31
1. Felder und Strings
Datentypen für Strings
Der Datentyp String
Zeichenketten können in Java mit dem Referenzdatentyp String dargestellt werden.
Zeichenketten vom Typ String haben die folgenden wesentlichen Eigenschaften:
☞ Die Länge eines Strings steht mit seiner Erzeugung fest und kann nachträglich
nicht geändert werden.
☞ Der Inhalt des Strings kann nicht geändert werden.
• Ein String ist eigentlich ein Objekt der Klasse java.lang.String.
• Für die Erzeugung kann die Literaldarstellung oder der new-Operator verwendet
werden.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
32
1. Felder und Strings
Datentypen für Strings
Varianten zur Erzeugung von String-Objekten:
String s1 = "abc";
String s2 = new String( "abc" );
char[] data = { ’a’, ’b’, ’c’ };
String s3 = new String( data );
byte[] b = { 97, 98, 99 };
String s4 = new String( b );
String s5 = new String( s4 );
Was liefert s1 == s2 oder s5 == s4?
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
33
1. Felder und Strings
Datentypen für Strings
Die Klasse String beinhaltet Methoden zum
• Zugriff auf einzelne Zeichen der Zeichenkette,
charAt(int index)
• Vergleich von Zeichenketten,
compareTo(String vergleichsString) und equals(String vergleichsString)
• Suchen von Teil-Zeichenketten,
indexOf(String teilString)
• Herausgreifen von Teil-Zeichenketten und
substring(int von) und substring(int von, int bis)
• Wandeln von Groß- in Kleinbuchstaben (und umgekehrt).
toLowerCase() und toUpperCase()
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
34
1. Felder und Strings
Datentypen für Strings
String s1 = "Weihnachten";
String s2 = "Weihnachten";
String s3 = "WEIHNACHTEN";
System.out.println(s1.charAt(4) );
System.out.println(s1.compareTo(s2) );
System.out.println(s1.compareTo(s3) );
System.out.println(s1.equals(s2) );
System.out.println(s1.indexOf("ach"));
System.out.println(s1.substring(3));
System.out.println(s1.substring(3,7));
System.out.println(s1.toUpperCase());
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
//
//
//
//
//
//
//
//
Ausgabe: n
Ausgabe: 0
Ausgabe: 1
Ausgabe: true
Ausgabe: 5
Ausgabe: hnachten
Ausgabe: hnac
Ausgabe:WEIHNACHTEN
35
1. Felder und Strings
Datentypen für Strings
Der Datentyp StringBuffer
• Die Klasse StringBuffer erlaubt es uns, mit veränderbaren ZeichenkettenObjekten zu arbeiten.
• Wir können beispielsweise zusätzliche Zeichen hinzufügen oder entfernen, ohne
das jeweils ein neues Objekt erzeugt wird.
• Während
String str = "";
for (int i=1; i<=500 ; i++ )
str = str + "x";
insgesamt 500 neue String-Objekte erzeugt, wird in den Zeilen
StringBuffer buf = new StringBuffer();
for (int i=1; i<=500 ; i++ )
buf.append("x");
nur ein einziges StringBuffer-Objekt erzeugt und verwendet.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
36
1. Felder und Strings
Datentypen für Strings
• Vorteil: effizienter
• Nachteil: komplexere Programmierung
• Konstruktoren von StringBuffer:
public StringBuffer()
public StringBuffer(String s)
• Einige Methoden:
– Aktuelle Länge: length()
– Etwas an die aktuelle Zeichenkette anhängen: verschiedene Varianten von
append, z.B.
StringBuffer append(int i)
– Einfügen an einer bestimmten Stelle: verschiedene Varianten von insert, z.B.
StringBuffer insert(int offset, int i)
– Teilstring löschen:
StringBuffer delete(int von, int bis)
• Genaueres erfahren Sie in der API-Dokumentation.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
37
2. Unterprogramme und Methoden
Methoden
2. Unterprogramme und Methoden
• Durch Methoden wird ausführbarer Code unter einem Namen zusammengefasst.
• Dieser Code kann unter Verwendung von sogenannten Parametern formuliert sein,
denen später beim Aufruf der Methode Werte übergeben werden.
• Methoden sind ein Bestandteil von Klassen.
• Wir befassen uns hier mit einem Spezialfall (Klassenmethoden)!
Später noch: Methoden in Verbindung mit Objekten
Beispiel: mehrfache Auswertung der Funktion
f (x, n) = x2n + n2 − nx
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
38
2. Unterprogramme und Methoden
Methoden
Deklaration von (Klassen-)Methoden
Syntax:
public static Rückgabetyp Methodenname ( Parameterliste ) {
Anweisungen
}
• Rückgabetyp
Datentyp des Ergebnisses, das die Methode zurückliefern soll.
Soll die Methode keinen Wert zurückliefern, verwenden wir hier void.
• Methodenname
Bezeichner als Name für die Methode.
• Parameterliste
Eine Kommaliste von Variablendeklarationen.
Die darin aufgeführten Variablen heißen formale Parameter.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
39
2. Unterprogramme und Methoden
Methoden
Parameterübergabe und -rückgabe
• Der Methodenkopf für die Berechnung von f (x, n) = x2n + n2 − nx könnte
lauten:
public static double f(double x, int n)
• Für die Ergebnisrückgabe an die aufrufende Umgebung steht die returnAnweisung zur Verfügung.
• Durch
return ergebnis;
wird die Ausführung der Methode beendet und der Wert des Ausdrucks ergebnis
als Resultat zurückgegeben.
• Hat eine Methode den Rückgabetyp void, so reicht
return;
Ein solches return als letze Anweisung kann auch entfallen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
40
2. Unterprogramme und Methoden
Methoden
• Eine Methode darf mehrere return-Anweisungen enthalten.
Für Methoden, die nicht den Rückgabetyp void haben, muß aber sichergestellt
sein, daß vor Beendigung der Methode eine return-Anweisung ausgeführt wird.
• Beispielmethode komplett:
public static double f(double x, int n) {
double produkt = 1.0;
for (int i=0; i<2*n ; i++)
produkt = produkt * x;
return produkt + n*n - n*x;
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
41
2. Unterprogramme und Methoden
Methoden
Aufruf von Methoden
Syntax:
Methodenname( Parameterliste )
• Ein Methodenaufruf ist ein elementarer Ausdruck.
• Parameterliste ist eine Kommaliste von Ausdrücken (aktuelle Parameter).
Die Werte der Ausdrücke werden über die formalen Parameter aus der Methodendeklaration an die Methode übergeben.
• Nach dem Aufruf wird jeweils der entsprechende Rückgabewert für den ursprünglichen Methodenaufruf eingesetzt und mit diesem Wert weitergearbeitet.
double y = f(x,n);
double z = f(y,3) + 3*x;
• In Java erfolgt die Parameterübergabe stets als Wertparameter (call by value). Es
wird stets eine Kopie des Wertes einer Variablen an die Methode übergeben, der
Wert der Variablen bleibt unverändert.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
42
2. Unterprogramme und Methoden
Methoden
Wertparameter
Wertparameter ermöglichen die Übergabe von Variablenwerten, aber nicht deren
Änderung.
Was wird ausgegeben?
public static void methode(int a) { a++; }
public static void main(String[] args) {
int a = 1;
methode(a);
System.out.println(a);
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
43
2. Unterprogramme und Methoden
Methoden
Referenzparameter
• Referenzparameter ermöglichen nicht nur die Übergabe von Variablenwerten, sondern auch deren Änderung.
• Referenzparameter gibt es z.B. in den folgenden Programmiersprachen: Pascal,
Modula-2, C++
• Durch die Benutzung von Zeigern (Referenzen) kann ein den Referenzparametern
ähnliches Verhalten simulieren.
• Aber Vorsicht: Auch die Referenzen sind nur Wertparameter in Java!
• Konsequenz: Nur die referenzierten Inhalte können geändert werden, nicht die Referenz selber!
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
44
2. Unterprogramme und Methoden
Methoden
Referenzparameter (2)
Was wird ausgegeben?
public static void methode(int[] a) { a[0]++; }
public static void main(String[] args) {
int[] a = { 1 };
methode(a);
System.out.println(a[0]);
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
45
2. Unterprogramme und Methoden
Methoden
Referenzparameter (3)
Was wird ausgegeben?
public static void methode(int[] a) {
a = new int[] { 2 };
}
public static void main(String[] args) {
int[] a = { 1 };
methode(a);
System.out.println(a[0]);
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
46
2. Unterprogramme und Methoden
Methoden
Überladen von Methoden
In Java darf es auch innerhalb einer Klasse mehrere Methoden mit dem gleichen
Namen geben, d.h. Methoden können überladen werden:
public static int max(int x, int y) {
return (x>y) ? x : y;
}
public static double max(double x, double y) {
return (x>y) ? x : y;
}
Java unterscheidet Methoden gleichen Namens
• anhand der Zahl der Parameter,
• anhand des Typs Typs der Parameter und
• anhand der Position der Parameter.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
47
2. Unterprogramme und Methoden
Methoden
Sichtbarkeit und Verdecken von Variablen
• Manchmal möchte man eine Variable deklarieren, die in mehr als einer Methode
(einer Klasse) bekannt ist.
• Wir erreichen dies, indem wir die Variable ausserhalb aller Methoden, aber innerhalb einer Klasse definieren und static davor schreiben.
public class MeineKlasse {
static String s = "Klassenvariable";
public static void meineMethode1() {
System.out.println(s);
}
public static void meineMethode2() {
System.out.println(s);
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
48
2. Unterprogramme und Methoden
Methoden
• Solch eine Variable heißt Klassenvariable.
• Java erlaubt es aber auch, daß Klassenvariablen und lokale Variablen bzw. Klassenvariablen und formale Parameter den gleichen Namen tragen.
• Wenn dies so ist, welche Variable wird dann genommen?
• Grundregel für die Sichtbarkeit bzw. das Verdecken:
Innerhalb von Methoden verdecken lokale Variablen und formale Parameter
die Klassenvariablen gleichen Namens.
• Klassenvariablen können trotzdem angesprochen werden. Hierzu stellt man den
Klassennamen vor den Variablennamen:
Klassenname.Variablenname
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
49
2. Unterprogramme und Methoden
public class VerdeckenTest {
static int a=1, b=2, c=3;
static int m(int a) {
int b=20;
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("c = " + c);
return 100;
}
public static void main(String[] args) {
int a=1000;
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("m(c) = " + m(c));
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
Methoden
Ausgabe:
a = 1000
b = 2
a = 3
b = 20
c = 3
m(c) = 100
50
2. Unterprogramme und Methoden
Methoden
Rekursive Methoden
Rekursion ist in Java erlaubt, d.h. Methoden dürfen sich selbst aufrufen!
Beispiel: Methode zur Berechnung der Fibonacci-Zahlen Fi :
F0 = 0, F1 = 1, Fn = Fn−1 + Fn−2 für n ≥ 2
static int fibonacci(int n) {
if ( n == 0 )
return 0;
if ( n == 1 )
return 1;
return fibonacci(n-1) + fibonacci(n-2);
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
51
2. Unterprogramme und Methoden
Methoden
Die Methode main
• Die Hauptmethode main ist nach dem gleichen Schema wie jede andere Methode
aufgebaut.
public static void main(String[] args)
• Der Inhalt von args ergibt sich durch die Argumente, die beim Aufruf des Programms angegeben werden.
• Beim Aufruf von
> java MeineKlasse Argument1 ... ArgumentN
gilt für args in main von MeineKlasse:
– args.length hat den Wert N
– args[0] hat den Wert Argument1 als String
– args[args.length-1] hat den Wert ArgumentN als String
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
52
3. Klassen
Klassen als strukturierter Datentyp
3. Klassen
Wir werden schrittweise unser Verständnis über Klassen erweitern:
•
•
•
•
•
Klassen als strukturierte Datentypen
Klassen als Konzept zur Kapselung
Instanzmethoden
Konstruktoren
statische Komponenten von Klassen
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
53
3. Klassen
Klassen als strukturierter Datentyp
Was sind Klassen?
• selbst definierter Datentyp (Referenzdatentyp)
• Modellierung neuer Strukturen
• Sammlung von Variablen verschiedener Typen
• Beispiel: Adresse
• Eine Adresse soll als Ganzes repräsentiert werden können.
• Teile des Ganzen haben unterschiedliche Datentypen.
• Eine Klasse fasst die Komponentenvariablen zusammen.
• Darstellung: UML-Klassendiagramm
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
Adresse
name:
strasse:
hausnummer:
postleitzahl:
wohnort:
mail:
kommentar:
String
String
int
int
String
String
String
54
3. Klassen
Klassen als strukturierter Datentyp
Erläuterungen und Terminologie:
• Die Komponentenvariablen heißen hier Instanzvariablen.
• Eine Klasse kann als Bauplan für Objekte verstanden werden.
• Eine konkrete Realisierung einer Klasse K bezeichnen wir als Instanz der Klasse
K bzw. als Objekt der Klasse K .
• Jedes Objekt verfügt über eine separate Version der Instanzvariablen.
• Komponentenvariablen, die in der Deklaration mit static versehen sind, sind dagegen Klassenvariablen (siehe voriges Kapitel).
• Klassenvariablen beschreiben üblicherweise eine Eigenschaft der Klasse, nicht eines einzelnen Objektes (später mehr).
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
55
3. Klassen
radius
farbe
Klassen als strukturierter Datentyp
radius = 1.0
farbe = blau
Kreis a
radius = 0.5
farbe = grün
Kreis b
radius = 1.3
farbe = rot
Kreis c
class Kreis
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
56
3. Klassen
Klassen als strukturierter Datentyp
Deklaration von Klassen
Syntax zur Deklaration von Klassen
(vorläufig):
public class Klassenname {
Variablendeklaration
...
Variablendeklaration
}
Beispiel:
public class Adresse {
String name;
String strasse;
int hausnummer;
int postleitzahl;
String wohnort;
String mail;
String kommentar;
}
1. Wir schreiben die Deklaration der Klasse Adresse in die Datei Adresse.java.
2. Wir compilieren Adresse.java. Damit entsteht Adresse.class.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
57
3. Klassen
Klassen als strukturierter Datentyp
3. Nun steht uns der neue Datentyp Adresse zur Verfügung. Eine Variablendeklaration der Form:
Adresse a;
ist nun möglich.
☞ Mit Klassen sind stets Referenzdatentypen verbunden.
☞ Also steht uns nach
Adresse a;
noch kein Objekt der Klasse Adresse zur Verfügung.
a
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
58
3. Klassen
Klassen als strukturierter Datentyp
Instanziierung von Objekten
Instanzen einer Klasse erzeugen wir mit dem new-Operator:
Variablenname = new Klassenname();
Man bezeichnet dies als Instanziierung.
Beispiel:
Adresse a;
a = new Adresse();
Natürlich ist es auch möglich, Variablendeklaration und Instanziierung in einer Anweisung zu formulieren:
Adresse a = new Adresse();
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
59
3. Klassen
Klassen als strukturierter Datentyp
Initialisierung von Instanzvariablen
a
name
☞ Instanzvariablen werden (automatisch) initialisiert wie Komponenten
von Feldern.
Hier:
• postleitzahl, hausnummer: 0
• und alle anderen Komponeten: null,
da Referenzdatentypen.
strasse
hausnummer
0
postleitzahl
0
wohnort
mail
kommentar
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
60
3. Klassen
Klassen als strukturierter Datentyp
Zugriff auf Instanzvariablen
Zugriff auf Komponenten eines Objekts:
Variablenname.Komponentenname
Beispiele:
Adresse a = new Adresse();
a.wohnort = "Musterhausen";
a.postleitzahl = 47111;
System.out.println( "PLZ: " + a.postleitzahl );
System.out.println( "Ort: " + a.wohnort );
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
61
3. Klassen
Klassen als strukturierter Datentyp
Objekte und Referenzen
Adresse a;
Adresse b;
a = new Adresse();
b = a;
a
name
b
• Klassen definieren Referenzdatentypen.
• Konsequenz: Eine Zuweisung sorgt
nicht dafür, dass ein Objekt kopiert
wird.
• Analog zu Feldern: Nur die Referenz
wird kopiert!
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
strasse
hausnummer
0
postleitzahl
0
wohnort
mail
kommentar
62
3. Klassen
Klassen als strukturierter Datentyp
Felder von Objekten
Natürlich können wir auch Felder deklarieren, die
als Komponententyp eine Klasse haben.
Adresse[] adressen = new Adresse[20];
• Der obige Aufruf erzeugt nur das Feld für
die Referenzen auf Instanzen von Adresse,
nicht die Objekte selbst.
• Die Feldkomponenten sind mit null initialisiert (siehe rechts).
• Erzeugung der Objekte:
for (int i=0 ; i<20 ; i++)
adressen[i] = new Adresse();
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
adressen
adressen[0]
adressen[1]
adressen[2]
adressen[17]
adressen[18]
adressen[19]
63
3. Klassen
Prinzipien der objektorientierten Programmierung
Prinzipien der objektorientierten Programmierung
• Objekte waren bisher nichts weiter als schlichte Datenspeicher, Klassen die Baupläne dieser Datenspeicher.
• In der objektorientierten Programmierung wird diese Sicht erweitert.
• Objekte sind hier mehr als reine Datenspeicher, sie haben insbesondere:
– einen Zustand und
– weisen ein bestimmtes Verhalten auf.
• Eine Klasse beschreibt die möglichen Zustände und das Verhalten der zugehörigen Instanzen. Sie ist eine abstrakte Beschreibung der Objekte (Instanzen).
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
64
3. Klassen
Prinzipien der objektorientierten Programmierung
Klassen als Modelle
• In der Softwareentwicklung transferieren wir die Problemwelt auf den Computer,
indem wir ein Modell der Problemwelt erstellen.
• Klassen sind wesentliche Bestandteile dieses Modells. Jede Klasse ist ein Modell
für eine Gruppe gleichartiger Objekte der Problemwelt.
• Durch die Instanziierung von Klassen erhalten wir Objekte. Diese Objekte stellen
auf dem Rechner das Äquivalent zu Gegenständen, Eigenschaften oder Personen
unserer Problemwelt dar.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
65
3. Klassen
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
Prinzipien der objektorientierten Programmierung
66
3. Klassen
Prinzipien der objektorientierten Programmierung
Vorteile des objektorientierten Ansatzes
• Ein Entwurf wird in unabhängige Komponenten (Klassen/Objekte) unterteilt, die
zusammen das Gesamtsystem bilden.
• Wie die Einzelteile eines Modellbaukastens werden diese Objekte zu einer Gesamtheit zusammengefügt.
Vorteile:
1. Durch die Aufteilung in (kleine) unabhängige Komponenten wird die Komplexität
verringert.
2. Die einzelnen Komponenten können unabhängig entwickelt und getestet werden.
3. Der Anbau weiterer Komponenten ist ohne besondere Probleme möglich.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
67
3. Klassen
Prinzipien der objektorientierten Programmierung
Grundpfeiler der objektorientierten Programmierung
•
•
•
•
Generalisierung
Vererbung
Kapselung
Polymorphismus
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
68
3. Klassen
Prinzipien der objektorientierten Programmierung
Kapselung
Grundidee der Kapselung: Vgl. Hinweis auf der Rückseite eines Fernsehgeräts:
Gerät steht unter Spannung und darf nur vom Fachmann geöffnet werden!
1. Das Öffnen des Geräts ist für Unbefugte nicht ungefährlich. Wollen Sie sich von
einem Fernsehmechaniker am Blinddarm operieren lassen?
2. Normale Benutzer sollten nicht wissen müssen, wie der Fernseher intern funktioniert. Hierzu dienen die Bedienelemente als Schnittstelle zur Außenwelt.
In der objektorientierten Programmierung:
1. Der interne Aufbau einer Klasse bleibt verborgen (Data Hiding). Zur Benutzung der
Klasse reichen Kenntnisse über deren Schnittstelle.
2. Der interne Aufbau einer Klasse kann geändert werden, ohne dass dies Auswirkungen auf andere Teile der Software hat.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
69
3. Klassen
Zugriffsrechte
Vom Referenzdatentyp zur Objektorientierung
Wir beginnen mit einer einfachen Klasse:
/** Diese Klasse repräsentiert Studierende */
public class Student {
Student
name:
nummer:
/** Der Name des/der Studierenden */
String name;
String
int
/** Matrikelnummer */
int nummer;
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
70
3. Klassen
Zugriffsrechte
Ist das Grundprinzip der Kapselung erfüllt?
• Haben wir die interne Struktur der Klasse Student von der Schnittstelle nach
außen getrennt?
• Könnten wir die Instanzvariablen einfach verändern, ohne hiermit Probleme zu verursachen?
Nein!
Wie können wir dies ändern?
• Anpassung der Zugriffsrechte für die Instanzvariablen.
• Deklaration von Zugriffsmethoden.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
71
3. Klassen
Zugriffsrechte
Zugriffsrechte
• Data Hiding: Wir wollen unsere Instanzvariablen vor der Außenwelt verstecken.
Bisher kann auch von anderen Klassen aus auf die Instanzvariablen von Student
zugegriffen werden.
• Dies wollen wir verhindern!
Hierzu schränken wir die Zugriffsrechte auf die Variablen ein.
• Zugriffsrecht wird private, d.h. nur innerhalb von Student ist ein Zugriff auf die
Instanzvariablen möglich.
Student
-name:
-nummer:
String
int
public class Student {
private String name;
private int nummer;
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
72
3. Klassen
Zugriffsrechte
Die Klasse AndereKlasse enthalte folgende Anweisungen:
Student studi = new Student();
studi.name = "Karla Karlsson";
studi.nummer = 4711;
Wenn wir versuchen, AndereKlasse zu übersetzen, erhalten wir einen Fehler der
Form:
Variable name in class Student not accessible
from class AndereKlasse.
Das heißt, die Zugriffe werden verweigert.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
73
3. Klassen
Instanzmethoden
Instanzmethoden
Wie können wir Daten aus Objekten auslesen oder zuweisen, wenn wir hierzu nicht
berechtigt sind?
☞ Wir erweitern die Klasse um Instanzmethoden.
• Instanzmethoden sind beim Aufruf stets an ein Objekt gebunden, d.h. wir rufen
eine Instanzmethode auf einem Objekt auf.
• Innerhalb der Instanzmethode haben wir Zugriff auf alle Instanzvariablen.
• Methoden haben ihre eigenen Zugriffsrechte.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
74
3. Klassen
Instanzmethoden
Syntax der Deklaration von öffentlichen Instanzmethoden:
public Rückgabetyp Methodenname ( Parameterliste ) {
Anweisungen
}
Beispiele:
public String getName() {
return name;
}
public int getNummer() {
return nummer;
}
public void setName( String name ) {
this.name = name;
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
75
3. Klassen
Instanzmethoden
public void setNummer( int n ) {
nummer = n;
}
Darstellung als Klassendiagramm:
Student
-name:
-nummer:
+getName()
+getNummer()
+setName(String)
+setNummer(int)
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
String
int
String
int
void
void
76
3. Klassen
Instanzmethoden
Was ist this?
• Das Schlüsselwort this liefert innerhalb
einer Instanzmethode immer eine Referenz auf das Objekt selbst, d.h. auf das
Objekt, auf dem die Methode aufgerufen
wurde.
• Das Schlüsselwort this wird insbesondere dann benötigt, wenn Instanzvariablen durch Namenskonflikte verdeckt werden.
Beispiel: Die Methode setName. Der formale Parameter name verdeckt die Instanzvariable name.
• Mittels this.name können wir die Instanzvariable ansprechen.
• Der Compiler “denkt ein wenig mit”. Liegen keine Namenskonflikte vor, ist die Angabe von this nicht notwendig.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
"Karla Karlsson"
name
nummer
4711
this
77
3. Klassen
Instanzmethoden
Instanzmethoden als erweiterte Funktionalität
Wir wollen die Menge der gültigen Matrikelnummern einschränken:
Eine Matrikelnummer sei dann gültig, wenn sie fünf Stellen sowie keine führenden Nullen hat und ungerade ist.
Hierfür definieren wir eine Methode validateNummer:
public boolean validateNummer() {
return (nummer >= 10000 && nummer <= 99999 && nummer % 2 != 0);
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
78
3. Klassen
Instanzmethoden
Wir können nun unsere Methode setNummer so ändern, dass nur noch gültige Matrikelnummern akzeptiert werden.
public void setNummer(int n) {
int alteNummer = nummer;
nummer = n;
if (!validateNummer())
nummer = alteNummer;
}
Bemerkungen:
• höhere Funktionalität
• ohne Datenkapselung nicht möglich
• keine Änderung an der Schnittstelle der Klasse Student
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
79
3. Klassen
Instanzmethoden
Beispiel: Ausgabe von Objekten auf der Konsole:
public String toString() {
return name + " (" + nummer + ")";
}
Nutzung:
Student studi = new Student();
studi.setName("Karla Karlsson");
studi.setNummer(12345);
System.out.println(studi.toString());
Prinzipiell reicht sogar die Anweisung:
System.out.println(studi);
Grund: Jedes Objekt verfügt automatisch über eine Methode toString, die für die
Ausgabe genutzt wird. Wir haben hier toString überschrieben.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
80
3. Klassen
Statische Komponenten einer Klasse
Klassenvariablen
• Wir wollen die Zahl der instantiierten Studentenobjekte zählen.
• Dies ist jedoch keine Eigenschaft eines einzelnen Objektes. Vielmehr gehört die
Eigenschaft zu der Gesamtheit aller Studentenobjekte.
• Eigenschaften einer Klasse als Ganzes werden durch Klassenvariablen repräsentiert.
Syntax für eine private Klassenvariable:
private static Datentyp Variablenname = Initialwert;
Beispiel:
private static int studZaehler = 0;
• Das Schlüsselwort static “macht” eine Variable zur Klassenvariable.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
81
3. Klassen
Statische Komponenten einer Klasse
• Wenn die Zugriffsrechte nicht dagegen sprechen, erfolgt der Zugriff auf eine Klassenvariable durch:
Klassenname.Variablenname
• Beispiel: Wäre studZaehler öffentlich, könnte man den Zählerwert wie folgt ausgeben:
System.out.println(Student.studZaehler);
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
82
3. Klassen
Statische Komponenten einer Klasse
Klassenmethoden
Für das Auslesen des Studentenzählers definieren wir eine öffentliche Klassenmethode:
public static int getZaehler() {
return studZaehler;
}
Nutzung der Klassenmethode:
System.out.println(Student.getZaehler());
• Eine Klassenmethode ist eine Methode, die der Klasse als Ganzes zugeordnet ist.
• In Klassenmethoden ist kein Zugriff auf Instanzvariablen möglich.
• Nutzung allgemein:
Klassenname.Methodenname( aktuelle Parameter )
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
83
3. Klassen
Statische Komponenten einer Klasse
Wie können wir dafür sorgen, dass bei der Erzeugung von Objekten der “Studentenzähler” korrekt erhöht wird?
Eine (noch nicht optimale) Möglichkeit: Wir “verpacken” die Erzeugung in einer Klassenmethode:
public static Student createStudent() {
studZaehler = studzaehler + 1;
return new Student();
}
Nutzung:
Student studi = Student.createStudent();
System.out.println(Student.getZaehler());
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
84
3. Klassen
• Warum nicht optimal? Bei älteren Programmen, die new verwenden, wird
der Zähler nicht erhöht.
• Wie können wir dies abstellen? Verwendung eines sogenannten Konstruktors (siehe folgendes Thema).
• Klassenmethoden und Klassenvariablen werden in Klassendiagrammen
durch Unterstreichung gekennzeichnet.
Statische Komponenten einer Klasse
Student
-name:
-nummer:
-studZaehler:
+getName()
+getNummer()
+setName(String)
+setNummer(int)
+validateNummer()
+toString()
+getZaehler()
+createStudent()
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
String
int
int
String
int
void
void
boolean
String
int
Student
85
3. Klassen
Statische Komponenten einer Klasse
Vereinbarung von Konstanten
• Die Vereinbarung von Konstanten erfolgt innerhalb einer Klassendefinition.
• Konstanten sind Klassenvariablen.
• Durch das Schlüsselwort final wird die nachträgliche Änderung des Variablenwerts verboten.
Syntax für die Deklaration öffentlicher Konstanten:
public static final Datentyp Variablenname = Initialwert;
Beispiel: Definition von Konstanten für Studienfächer:
public static final int MATHEMATIK STUDIUM = 1;
public static final int INFORMATIK STUDIUM = 2;
public static final int BIOLOGIE STUDIUM = 3;
...
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
86
3. Klassen
Statische Komponenten einer Klasse
• Der Zugriff erfolgt wie bei Klassenvariablen:
Klassenname.Variablenname
• Es hat sich die Schreibweise durchgesetzt, dass Konstantennamen ausschließlich
aus Großbuchstaben und Unterstrichen bestehen. Teilwörter werden durch einen
Unterstrich getrennt (siehe Java Code Conventions).
• Die Zuweisung an eine als Konstante vereinbarte Variable führt zu einem Fehler
bei der Übersetzung.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
87
3. Klassen
Konstruktor
Konstruktor
• Mit Konstruktoren können wir Einfluss auf die Erzeugung eines Objektes nehmen.
• Konstruktoren erlauben es, den Anfangszustand von Objekten zu parametrisieren.
• Der Aufruf des/der Konstruktoren erfolgt implizit bei Anwendung von new.
Syntax für einen öffentlichen Konstruktor:
public Klassenname( Parameterliste )
{
Anweisungen
}
• Ein Konstruktor heißt immer so wie die Klasse.
• In der Parameterliste werden Argumente vereinbart.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
88
3. Klassen
Konstruktor
Der einfachste Konstruktor für Student lautet:
public Student() { }
Allgemein ist dies der Standard-Konstruktor. Er wird automatisch angelegt, wenn kein
Konstruktor definiert wurde (aber nur genau für diesen Fall).
Wir sollten im Konstruktor dafür sorgen, dass automatisch der Zähler für die Studentenobjekte erhöht wird.
public Student() {
studZaehler = studZaehler + 1;
}
Damit ist die Klassenmethode createStudent überflüssig.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
89
3. Klassen
Konstruktor
Überladen von Konstruktoren
• Wie Methoden können auch Konstruktoren überladen werden.
• D.h., es darf mehrere Konstruktoren zu einer Klasse geben.
• Diese müssen sich aber in ihrer Signatur unterscheiden.
Weiterer möglicher Konstruktor für Student:
public Student(String name, int nummer) {
studZaehler = studZaehler + 1;
this.name = name;
this.nummer = nummer;
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
90
3. Klassen
Konstruktor
• Innerhalb eines Konstruktors darf als erste Anweisung ein anderer Konstruktor aufgerufen werden.
• Dies erfolgt durch das Schlüsselwort this in Verbindung mit aktuellen Parametern.
Beispiel:
public Student(String name, int nummer) {
this();
this.name = name;
this.nummer = nummer;
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
91
3. Klassen
Statische Komponenten einer Klasse
Der statische Initialisierer
• Ein Konstruktor ermöglicht uns eine objektbezogene Initialisierung.
• Gibt es auch eine klassenbezogene Initialisierung?
• Ja, mit Hilfe des statischen Initialisierers.
Syntax:
static
{
Anweisungen
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
92
3. Klassen
Statische Komponenten einer Klasse
• Ein statischer Initialisierer einer Klasse wird ausgeführt, wenn die Klasse geladen
wird.
• Eine Klasse wird vom Class Loader der virtuellen Maschinene geladen, wenn sie
das erste mal benötigt wird.
• Eine Klasse kann mehrere statische Initialisierer haben.
Für die Anweisungen gelten die Einschränkungen eines statischen Kontextes:
• Nur Zugriff auf statische Komponenten einer Klasse.
• Zugriff auf alle (auch private) Teile einer Klasse.
• Weitere Einschränkung: Statische Initialisierer haben nur Zugriff auf statische Komponenten, die im Programmcode vor ihnen definiert wurden.
☞ Beispiel zum statischen Initialisierer.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
93
3. Klassen
Beispiele
Nutzen der Kapselung
Wenn wir Programmlogik in einem Objekt kapseln, dann können wir
1. diese Logik mehrmals zur gleichen Zeit einsetzen,
Beispiel: gleichzeitig mehrere unabhängige Objekte
2. in unterschiedlichen Zusammenhängen nutzen und
Beispiel: Programm zum Zählen von Zeilen, Wörtern und Zeichen
3. komplexere Objekte aus einfacheren Objekten zusammensetzen.
Beispiel: Die Klassen TorZaehler und Spielstand
☞ Leichtere Wiederverwendbarkeit
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
94
3. Klassen
Beispiele
Weitere Beispiele:
• Klausuraufgabe Skyline
Entwerfen Sie eine Klasse zur Ermittlung der Skyline, die von einer Menge von
Gebäuden erzeugt wird.
5
5
0
5
10
15
0
Gebäude
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
5
10
15
Skyline
95
3. Klassen
Beispiele
– Die Skyline reicht in der Breite von 0 bis B .
– Jedes Gebäude wird beschreiben durch ein Tripel (l, h, r) mit 0 ≤ l < r ≤ B .
Hierbei ist l der linke Rand, r der rechte Rand und h die Höhe des Gebäudes.
– Die oben angegebene Skyline wird beispielsweise durch B = 15 und die
Gebäude (3, 3, 10), (6, 6, 12), (11, 4, 14) erzeugt.
Die Klasse soll die folgenden Methoden aufweisen:
– Ermittlung der Breite B der Skyline.
– Einfügen eines Gebäudes (l, h, r) in die Skyline.
– Ermittlung der Höhe der Skyline an der Stelle i.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
96
3. Klassen
Beispiele
• Klausuraufgabe TextSpeicher
Definieren Sie eine Klasse für die Speicherung von Texten. Ein Objekt Ihrer
Klasse soll bis zu 15 Texte speichern können. Jedem Text ist dabei eine
Position im Speicher zugeordnet. Für die Verwaltung der Texte sollen die
folgenden Methoden zur Verfügung stehen:
– Löschen eines Textes
Der Text an Position i wird aus dem Speicher entfernt. Alle Texte mit einer
Position größer als i rücken um eine Position nach vorne.
– Speichern eines Textes
Der Text wird an der ersten freien Position gespeichert. Ist der Textspeicher
voll, so wird der an der ersten Position gespeicherte Text gelöscht und der
neue Text wird als letzter Text im Speicher abgelegt.
– Rückgabe des Textes an Position i
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
97
4. Vererbung
Grundlagen der Vererbung
4. Vererbung
Wir wollen ein Verwaltungsprogramm für CDs und Videos entwickeln. Wir stellen uns
dazu folgende Klassen vor:
CD
titel:
kuenstler:
titelanzahl:
spielzeit:
habIch:
kommentar:
setzeKommentar(String)
gibKommentar()
setzeVorhanden(boolean)
gibVorhanden()
ausgeben()
String
String
int
int
boolean
String
void
String
void
boolean
void
Video
titel:
regisseur:
spielzeit:
habIch:
kommentar:
setzeKommentar(String)
gibKommentar()
setzeVorhanden(boolean)
gibVorhanden()
ausgeben()
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
String
String
int
boolean
String
void
String
void
boolean
void
98
4. Vererbung
Grundlagen der Vererbung
Wenn wir diese beiden Klassen realisieren, stellen wir fest, dass der Quelltext der
Klassen weitgehend identisch ist.
☞ siehe Beispiele
Nachteile dieses Ansatzes:
• erhöhter Aufwand der Erstellung
• bei der Wartung von dupliziertem Code sind Änderungen an mehreren Stellen notwendig
• Wartung ist fehleranfällig
• erhöhter Testaufwand
• erhöhter Aufwand bei der Nutzung der Klassen
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
99
4. Vererbung
Grundlagen der Vererbung
Idee der Vererbung
• Statt die beiden Klassen CD und Video unabhängig voneinander zu definieren,
definieren wir zuerst eine Klasse, die die Gemeinsamkeiten von CD und Video
zusammenfasst.
Wir wollen diese Klasse Medium nennen.
• Wir definieren dann anschließend, dass eine CD ein Medium ist und ebenso, dass
ein Video ein Medium ist.
• Schließlich ergänzen wir die Klassen für CD und Video ausschließlich um ihre
spezifischen Eigenschaften.
☞ Prinzip der Generalisierung
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
100
4. Vererbung
Grundlagen der Vererbung
Medium
−titel: String
−spielzeit: int
−habIch: boolean
−kommentar: String
+void setzeKommentar(String)
+String gibKommentar()
+void setzeVorhanden(boolean)
+boolean gibVorhanden()
+void ausgeben()
CD
−kuenstler: String
−titelanzahl: int
Video
−regisseur: String
+String gibRegisseur()
+String gibKuenstler()
+int gibTitelanzahl()
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
101
4. Vererbung
Grundlagen der Vererbung
Terminologie
• Eine Superklasse (Oberklasse) ist eine Klasse, die von anderen Klassen erweitert
wird.
• Eine Subklasse (Unterklasse) ist eine Klasse, die eine andere Klasse erweitert.
Man sagt auch, dass die Subklasse von der Superklasse erbt.
• Vererbung bedeutet, dass die Subklasse alle Datenfelder und Methoden von der
Superklasse übernimmt.
• Es werden keine Konstruktoren vererbt!
• Klassen, die über eine Vererbungsbeziehung miteinander verknüpft sind, bilden
eine Vererbungshierarchie.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
102
4. Vererbung
Grundlagen der Vererbung
Beispiel:
Eine
Vererbungshierarchie für graphische
Elemente.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
103
4. Vererbung
Vererbung in Java
Vererbung in Java
Syntax:
public class Unterklasse extends Oberklasse {
...
}
• Mit Hilfe von extends wird die Oberklasse zu einer Klasse angegeben.
• Java unterstützt ausschließlich einfache Vererbung, d.h. wir können höchstens eine
Oberklasse angeben.
• Ohne Verwendung von extends ist implizit die Klasse java.lang.Object die
Oberklasse.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
104
4. Vererbung
Vererbung in Java
Definition der Oberklasse Medium:
Definition der Unterklassen:
public class Medium {
private String titel;
private int spielzeit;
private boolean habIch;
private String kommentar;
...
}
public class CD extends Medium {
private String kuenstler;
private int titelanzahl;
...
}
public class Video extends Medium {
private String regisseur;
...
}
☞ In den Unterklassen werden zusätzliche Datenfelder und Methoden deklariert.
☞ Darüberhinaus verfügt ein Objekt der Unterklasse über alle Datenfelder und Methoden der Oberklasse.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
105
4. Vererbung
Vererbung in Java
Vererbung und Zugriffsrechte
• Von einer Unterklasse aus kann man nicht auf die private deklarierten Datenfelder und Methoden der Oberklasse zugreifen.
• Daher gibt es zusätzlich den Modifikator (Zugriffsrecht) protected.
• Das Zugriffsrecht protected
– erlaubt den Zugriff von Unterklassen aus,
– erlaubt den Zugriff für Klassen des gleichen Pakets und
– verbietet den Zugriff für alle anderen Klassen.
• Der Modifikator protected kann nur auf Datenfelder, Konstruktoren und Methoden angewendet werden, nicht auf Klassen.
• Datenfelder werden üblicherweise nicht als protected deklariert, da dies die
Kapselung schwächen würde. Stattdessen definiert man Zugriffsmethoden die
protected oder public sind.
• Typischer Einsatz von protected: Bei Hilfsmethoden, die nach außen verborgen
werden sollen, für Unterklassen aber hilfreich sein können.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
106
4. Vererbung
Vererbung in Java
• Der Einsatz von protected ist nur über Paketgrenzen hinweg sinnvoll.
• protected wird deutlich seltener als public und private eingesetzt.
• Bevor Sie protected verwenden, sollten Sie kritisch prüfen, ob private nicht
auch ausreicht.
• Man beachte: protected ist weniger restriktiv als die Verwendung keines Modifikators.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
107
4. Vererbung
Vererbung in Java
Vererbung und Initialisierung
• Üblicherweise sorgt ein Konstruktor dafür, dass die Datenfelder eines Objekts nach
der Erzeugung in einem vernüftigem Zustand sind.
• Wie ist das nun, wenn die Datenfelder durch Vererbung über verschiedene Klassen
verteilt sind?
• Unter- und Oberklasse bieten Konstruktoren an.
• Die Unterklasse kümmert sich in ihrem Konstruktor nur um die Datenfelder, die in
der Unterklasse definiert sind.
• Damit auch die Datenfelder der Oberklasse korrekt initialisiert werden, rufen wir
den Konstruktor der Oberklasse auf.
• Der Aufruf des Konstruktors der Oberklasse erfolgt mit dem Schlüsselwort super.
• Dieser Aufruf muss stets die erste Anweisung in einem Konstruktor der Unterklasse
sein! Ansonsten fügt der Compiler den Aufruf eines parameterlosen Konstruktors
für die Oberklasse ein.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
108
4. Vererbung
Vererbung in Java
public class Medium {
private
private
private
private
String titel;
int spielzeit;
boolean habIch;
String kommentar;
public Medium(String titel, int spielzeit)
{
this.title = titel;
this.spielzeit = spielzeit;
this.habIch = false;
this.kommentar = "";
}
...
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
109
4. Vererbung
Vererbung in Java
public class CD extends Medium {
private String kuenstler;
private int titelanzahl;
public CD(String titel, String kuenstler, int stuecke, int spielzeit)
{
super(title,spielzeit);
this.kuenstler = kuenstler;
this.titelanahl = stuecke;
}
...
}
☞ Sie sollten den Konstruktor der Oberklasse auch dann explizit aufrufen, wenn der
Compiler diesen Aufruf automatisch einfügen würde. Es ist guter Programmierstil.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
110
4. Vererbung
Vererbung in Java
Vorteile der Vererbung (bis hierher)
•
•
•
•
Vermeidung von Quelltext-Duplizierung
Wiederverwendung von Quelltext
Einfachere Wartung
Erweiterbarkeit
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
111
4. Vererbung
Subtyping
Subtyping und Ersetzbarkeit
• Wir wissen: Klassen definieren Datentypen.
• Wir haben gelernt: Klassen bilden eine Klassenhierarchie.
• Analog zur Klassenhierarchie entsteht somit auch eine Typhierarchie mit Suptypen
(Untertypen) und Supertypen (Obertypen).
• Der Typ, der durch eine Subklasse definiert wird, ist ein Subtyp des Typs, der durch
die Zugeordnete Superklasse definiert wird.
Prinzip der Ersetzbarkeit:
Objekte von Subtypen können an allen Stellen verwendet werden, an denen ein
Supertyp erwartet wird.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
112
4. Vererbung
Subtyping
Beispiel: Die folgenden Zuweisungen sind zulässig:
Medium medium = new Medium(...);
Medium cd
= new CD(...);
Medium video = new Video(...);
• Eine Variable kann Objekte halten, deren Typ entweder gleich dem deklarierten
Typ der Variablen ist oder ein beliebiger Subtyp des deklarierten Typs ist.
• Bei der Zuweisung wird eine implizite Typumwandlung (Cast) durchgeführt.
Umgekehrt gilt dies nicht. Die folgenden Anweisungen sind nicht zulässig:
CD cd = new Medium(...);
Video video = new CD(...);
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
113
4. Vererbung
Subtyping
Dieses Prinzip der Ersetzbarkeit gilt natürlich auch bei einer Parameterübergabe.
public class MedienDatenbank {
...
public void einfuegen(Medium medium) {
...
}
}
Wir können diese Methode sowohl für Videos als auch für CDs verwenden.
MedienDatenbank db = new MedienDatenbank(...);
Video video = new Video(...);
CD cd = new CD(...);
db.einfuegen(video);
db.einfuegen(cd);
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
114
4. Vererbung
Subtyping
• Variablen für Objekte sind in Java polymorphe Variablen.
• Der Ausdruck polymorph (vielgestaltig) bezieht sich auf die Tatsache, dass eine
Variable Objekte verschiedener Typen referenzieren kann.
• Polymorphie ist einer der Grundpfeiler der Objektorientierung.
• Polymorphie tritt in objektorientierten Sprachen in unterschiedlichen Zusammenhängen auf.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
115
4. Vererbung
Überschreiben von Methoden
Überschreiben von Methoden
Die Methode ausgeben() in der Klasse Medium können wir folgendermaßen definieren:
public void ausgeben() {
System.out.print(titel + " (" + spielzeit + "Min)");
if (habIch)
System.out.println("*");
else
System.out.println();
System.out.println("
" + kommentar);
}
Jetzt erzeugen wir eine Instanz der Klasse CD:
CD cd = new CD("Beggar\’s Banquet", "Rolling Stones", 10, 41);
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
116
4. Vererbung
Überschreiben von Methoden
Mit weiteren Anweisungen können wir einen Kommentar angeben und das wir im Besitz der CD ist. Die Anweisung
cd.ausgeben();
erzeugt dann die Ausgabe
Beggar’s Banquet (41 Min)*
Die letzte Platte der Ur-Stones, ein absolutes Meisterwerk!
Problem:
• Die Ausgabe ist unzureichend.
• Es werden nur die allgemeinen Informationen angezeigt, die in der Klasse Medium
definiert sind.
• Dedizierte CD-Informationen (Künstler, Titelanzahl) fehlen in der Ausgabe.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
117
4. Vererbung
Überschreiben von Methoden
• Um eine vernüftige Ausgabe für CDs zu erhalten, müssen wir die Methode
ausgeben() überschreiben.
• Eine Subklasse kann die Implementierung einer Methode überschreiben.
• Dazu deklariert die Subklasse eine Methode mit der gleichen Signatur wie in der
Superklasse, implementiert diese jedoch mit einem anderen Rumpf.
• Bei Aufrufen an Objekte der Unterklasse wird die überschreibende Methode ausgeführt.
Ein erster Versuch:
public class CD extends Medium {
...
public void ausgeben() {
System.out.println( "
" + kuenstler +
", " + titelanzahl + " Titel");
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
118
4. Vererbung
Überschreiben von Methoden
Die Anweisung cd.ausgeben(); liefert jetzt:
Rolling Stones, 10 Titel
• Jetzt geben wir nur die CD-spezifischen Information aus, es fehlen die allgemeinen
Informationen.
• Auf die Instanzvariablen von Medium haben wir aber innerhalb von CD keinen
Zugriff. Sollte man diese protected deklarieren?
• Nein, u.U. können wir dies auch gar nicht, da wir nicht den Quelltext von Medium
besitzen.
• Stattdessen nutzen wir super, um innerhalb der überschreibenden Methode, die
Methode der Oberklasse aufzurufen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
119
4. Vererbung
Überschreiben von Methoden
Ein zweiter Versuch:
public class CD extends Medium {
...
public void ausgeben() {
System.out.print("CD: " + kuenstler + ": ");
super.ausgeben();
System.out.println( "
" + titelanzahl + " Titel");
}
}
Jetzt liefert die Anweisung cd.ausgeben();:
CD: Rolling Stones: Beggar’s Banquet (41 Min)*
Die letzte Platte der Ur-Stones, ein absolutes Meisterwerk!
10 Titel
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
120
4. Vererbung
Überschreiben von Methoden
• Ein super-Aufruf in einer Methode hat immer folgende Form:
super.Methodenname( Parameterliste );
Der Methodenname muss also explizit genannt werden.
• Im Gegensatz zu super-Aufrufen in Konstruktoren kann der super-Aufruf in einer
Methode an jeder beliebigen Stelle der Methode erfolgen.
• Es muss auch kein super-Aufruf erfolgen und wenn dieser nicht erfolgt, wird auch
nicht automatisch ein solcher Aufruf generiert.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
121
4. Vererbung
Überschreiben von Methoden
Vererbung und Methodenausführung
Medium medium = new CD("Beggar\’s Banquet", "Rolling Stones", 10, 41);
...
medium.ausgeben();
• Welche Methode ausgeben() wird hier ausgeführt?
Die der Klasse Medium, weil die Variable medium von diesem Typ ist?
☞ statischer Typ der Variablen medium
Die der Klasse CD, weil das Objekt, auf dem ausgeben() aufgerufen wird, eine
Instanz von CD ist?
☞ dynamischer Typ der Variablen medium
☞ Entscheidend für die Methodenauswahl ist der dynamische Typ einer Variablen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
122
4. Vererbung
Überschreiben von Methoden
Methoden-Polymorphie:
• Methodenaufrufe in Java sind polymorph.
• Derselbe Methodenaufruf kann zu unterschiedlichen Zeitpunkten verschiedene
Methoden aufrufen.
• Welche Methode tatsächlich aufgerufen wird, ist abhängig vom dynamischen Typ
der Variablen, mit der der Aufruf durchgeführt wird.
Weiteres Beispiel:
• Wir gehen davon aus, daß die Klassen
CD und Video die Methode ausgeben()
aus Medium überschreiben.
• Dann wird für i==0 die Methode
ausgeben() von CD aufgerufen und
• für i==1 die Methode ausgeben() von
Video.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
Medium m;
Medium m1 = new CD(...);
Medium m2 = new Video(...);
for (int i=0 ; i<2 ; i++) {
if (i==0)
m = m1;
else
m = m2;
m.ausgeben();
}
123
4. Vererbung
Überschreiben von Methoden
Wir wollen die Frage, welche Instanzmethode bei einem Methodenaufruf aufgerufen
wird, wird noch etwas genauer betrachten.
Methodensuche:
• Beim Aufruf einer Instanzmethode findet eine sogenannte Methodensuche statt.
• Ausgehend vom dynamischen Typ der Variablen wird in der Vererbungshierarchie
nach einer Methode gesucht, die auf die Signatur des Aufrufs passt.
• Wenn die Klasse des dynamischen Typs keine solche Methode aufweist, wird in
der direkten Oberklasse gesucht, usw.
• Die Suche endet spätestens in der Klasse Object.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
124
4. Vererbung
Die Klasse Object
Die Klasse Object
• Alle Klassen ohne explizit deklarierte Superklasse haben die Klasse Object als
Superklasse.
• Object gehört zum Paket java.lang.
• Object verfügt über einige vordefinierte Methoden. Diese stehen somit allen Objekten (auch Feldern) zur Verfügung.
• Es kann sinnvoll sein, diese Methoden in Unterklassen zu überschreiben, d.h. mit
einer anderen Implementierung zu versehen.
• Beispiel: toString()
• genaueres zu den Methoden: siehe API-Dokumentation
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
125
4. Vererbung
Die Klasse Object
Die Methode equals
public boolean equals(Object vergleichsObjekt)
• Äquivalenzrelation auf nicht null Objekten.
• Implementierung in Object:
return this == vergleichsObjekt;
• Überschreiben in Unterklassen: inhaltlicher Vergleich
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
126
4. Vererbung
Die Klasse Object
Die Methode toString
public String toString()
• toString() wird implizit aufgerufen, wenn eine Objektreferenz als Parameter der
Methode println() verwendet wird.
MeineKlasse obj = new MeineKlasse();
System.out.println(obj);
• Die Implementierung in Object liefert einen String der Art:
Klassenname@Referenz
• Hier bietet es sich an, in Unterklassen die Methode toString zu überschreiben.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
127
4. Vererbung
Die Klasse Object
Die Methode finalize
protected void finalize()
•
•
•
•
Wird vom Garbage Collector auf einem Objekt aufgerufen.
Aufruf erfolgt, wenn nicht mehr auf das Objekt zugegriffen werden kann.
finalize der Klasse Object macht nichts.
Kann in Unterklassen überschrieben werden, um Aufräumarbeiten durchzuführen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
128
4. Vererbung
Die Klasse Object
Die Methode hashCode
public int hashCode()
•
•
•
•
•
Liefert einen Hash-Wert, d.h. eine nahezu eindeutige Kennung für ein Objekt.
Unterstützung für Hashing (siehe 3. Semester, AlgoDat)
Selbes Objekt liefert stets den gleichen Hashwert
Objekte, für die equals den Wert true liefert, müssen gleichen Hash-Wert haben.
Verschiedene Objekte müssen nicht verschiedene Hash-Werte haben.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
129
4. Vererbung
Finale Klassen und finale Methoden
Finale Klassen
•
•
•
•
•
Der Modifier final schützt Klassen vor Vererbung.
public final class Klasse { ... }
Wirkung: Von Klasse kann keine Unterklasse abgeleitet werden.
Typischerweise sind Klassen, die nur static Definitionen enthalten, final.
Beispiel: java.lang.Math
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
130
4. Vererbung
Finale Klassen und finale Methoden
Finale Methoden
• final vor einer Methode schützt diese Methode vor dem Überschreiben.
• public final void meineMethode()
• Finale Methoden verwendet man, wenn man sicherstellen möchte, dass eine Methode nicht verändert wird, z.B. weil Sie kritisch für den Zustand eines Objektes
ist.
• class ChessAlgorithm {
static final int WHITE = 0;
static final int BLACK = 1;
...
final int getFirstPlayer() {
return ChessAlgorithm.WHITE;
}
...
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
131
4. Vererbung
Typumwandlungen
Sichtbarkeit von Methoden
Medium medium = new CD("Beggarś Banquet", "Rolling Stones", 10, 41);
System.out.println(medium.gibKuenstler());
Problem:
• Das erzeugte CD-Objekt hat zwar eine Methode gibKuenstler(),
• diese ist aber über die Variable medium nicht sichtbar.
✎ Compiler liefert Fehler
Ursache: Die Variable medium könnte auch Objekte referenzieren, die nicht aus der
Klasse CD stammen.
✎ Entscheidend für die Sichtbarkeit ist der statische Typ einer Variablen
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
132
4. Vererbung
Typumwandlungen
Typumwandlungen
Kann man aus dem Medium-Objekt wieder ein CD-Objekt machen? Ja, mit einer expliziten Typumwandlung.
Medium medium = new CD("Beggarś Banquet", "Rolling Stones", 10, 41);
...
CD
cd
= (CD) medium;
System.out.println(cd.gibKuenstler());
oder kurz
System.out.println( ((CD)medium).gibKuenstler() );
• Eine (typischerweise implizite) Typumwandlung von einem Untertyp zu einem
Obertyp heißt Upcast.
• Eine (nur explizit mögliche) Typumwandlung von einem Obertyp zu einem Untertyp
heißt Downcast.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
133
4. Vererbung
Typumwandlungen
Typumwandlung (2)
public class OK { ... }
public class UK1 extends OK { ... }
public class UK2 extends OK { ... }
OK a = new UK1();
OK b = new UK2();
UK1 c = (UK1) a;
UK2 d = (UK2) b;
UK2 e = (UK2) c;
UK2 f = (UK2) a;
//
//
//
//
//
//
ok, Upcast
ok, Upcast
ok, Downcast
ok, Downcast
Fehler, erkennt Compiler
Fehler, ClassCastException
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
134
4. Vererbung
Typumwandlungen
Typumandlung bei Feldern
• Die Typhierarchie setzt sich auf Felder fort.
• Wenn OK eine Oberklasse von UK ist, dann ist OK[] ein Obertyp von UK[].
Medium[] medienliste = new CD[20];
medienliste[0] = new CD(...);
CD cd = (CD) medienliste[0];
medienliste[1] = new Video(...);
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
//
//
//
//
ok, Upcast
ok, Upcast
ok, Downcast
Fehler, ClassCastException
135
4. Vererbung
Typumwandlungen
Der instanceof-Operator
• zweistelliger Operator, der einen boolschen Wert liefert
• Syntax:
Ausdruck instanceof Referenztyp
• Liefert true, wenn ein Cast von Ausdruck zu Referenztyp möglich ist.
• Hierdurch kann eine ClassCastException vermieden werden.
• Auch als Test möglich, um zu prüfen, ob ein Objekt aus einer bestimmten Unterklasse stammt.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
136
4. Vererbung
Typumwandlungen
Der instanceof-Operator (2)
Beispiel:
MedienDatenbank db = new MedienDatenbank(...);
Medium[]
medienliste = db.gibAlleMedien();
CD
cd;
Video
video;
for (int i=0 ; i<medienliste.length ; i++)
if ( medienliste[i] instanceof CD ) {
cd = (CD) medienliste[i];
System.out.println(cd.gibKuenstler());
}
else if ( medienliste[i] instanceof Video ) {
video = (Video)medienliste[i];
System.out.println(video.gibRegisseur());
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
137
5. Abstrakte Klassen
Beispiel
5. Abstrakte Klassen
Angenommen, wir wollen die folgende Klassenhierarchie implementieren:
Vogel
+ singe()
Amsel
Drossel
Fink
+ singe()
+ singe()
+ singe()
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
138
5. Abstrakte Klassen
Beispiel
Beispiel (2)
Vorschlag zur Implementierung:
public class Vogel {
public void singe() { System.out.println( "Vogel singt: ..."); }
}
public class Amsel extends Vogel {
public void singe() { System.out.println( "Amsel singt: uiuiii..."); }
}
public class Drossel extends Vogel {
public void singe() { System.out.println( "Drossel singt: zwawaaa..."); }
}
public class Fink extends Vogel {
public void singe() { System.out.println( "Fink singt: zrzrrr..."); }
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
139
5. Abstrakte Klassen
Beispiel
Beispiel (3)
Probleme des Implementierungsvorschlags:
(1) In der Realität gibt es keinen Vogel, der “nur” ein Vogel ist.
Konsequenz: Nur für die Unterklassen sollte eine Instanziierung möglich sein.
(2) Ein Programmierer erweitert die Klassenhierarchie um die Klasse Star und vergisst dabei, die Methode singe() zu überschreiben.
Dann haben Stare keine Stimme.
(3) Wenn (1) erfüllt ist und der Fehler von (2) nicht vorliegt, dann wird die Methode
singe() in der Klasse Vogel nie aufgerufen.
Wir können Sie aber auch nicht einfach weglassen. Warum nicht?
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
140
5. Abstrakte Klassen
Abstrakte Klasse
Abstrakte Klasse
• Problem (1) können wir lösen, indem wir eine Klasse als abstrakt kennzeichnen.
• Zugehöriges Schlüsselwort: abstract
public abstract class Klassenname ... { ... }
• Von abstrakten Klassen können keine Instanzen erzeugt werden.
• Konsequenz: Um Objekte erzeugen zu können, muss mindestens eine Unterklasse
zur abstrakten Klasse definiert werden, die nicht mehr abstrakt ist.
Für unser Beispiel:
• Wenn wir die Klasse Vogel als abstrakt kennzeichnen, können wir nur noch Amseln, Drosseln oder Finken instanziieren.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
141
5. Abstrakte Klassen
Abstrakte Klasse
Abstrakte Klasse (2)
Bemerkungen:
• Eine abstrakte Klasse kann Unterklasse einer nicht abstrakten Klasse sein.
• Eine abstrakte Klasse kann weitere abstrakte Klassen als Unterklassen haben.
• Auch für abstrakte Klassen sollten Konstruktoren definiert werden.
Grund: Die Initialisierung von Objekten erfolgt entlang der Klassenhierarchie (siehe
Beispiel zu geometrischen Objekten).
• Eine Klasse kann nicht gleichzeitig final und abstrakt sein.
Konsequenz: Der Compiler verbietet die Kombination von abstract und final
im Klassenkopf.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
142
5. Abstrakte Klassen
Abstrakte Klasse
Abstrakte Klasse in UML
Im UML-Klassendiagramm werden abstrakte Klassen durch einen kursiven Klassennamen gekennzeichnet.
Vogel
+ singe()
Amsel
Drossel
Fink
+ singe()
+ singe()
+ singe()
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
143
5. Abstrakte Klassen
Abstrakte Methoden
Abstrakte Methoden
Zur Lösung der Probleme (2) und (3) erklären wir die Methode singe() in der Klasse
Vogel zu einer abstrakten Methode.
• Die Definition einer abstrakten Methode besteht aus einer Methodensignatur ohne
einen Rumpf.
• Statt eines Blocks als Rumpf folgt dem Methodenkopf ein Semikolon.
• Solch eine Methode wird mit dem Schlüsselwort abstract markiert.
• Damit haben wir Problem (3) gelöst: Wir brauchen keine Dummy-Implementierung
mehr für die Methode singe().
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
144
5. Abstrakte Klassen
Abstrakte Methoden
Abstrakte Methoden (2)
Syntax:
Modifikator abstract Datentyp Methodenname(Parameterliste);
Beispiel: Abstrakte Klasse mit einer abstrakten Methode:
public abstract class Vogel {
public abstract void singe();
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
145
5. Abstrakte Klassen
Abstrakte Methoden
Abstrakte Methoden (3)
Die Definition einer abstrakten Methode m in einer Klasse K bedeutet:
• Für die Klasse K und somit auch für alle Unterklassen U von K ist die Methode
m bekannt.
• K möchte/kann die Methode nicht implementieren. Dies muss in einer Unterklassen U von K erfolgen.
• Sei U eine (nicht abstrakte) Unterklasse von K . Dann ist folgendes möglich.
K k = new U();
k.m();
• Die Methodenauswahl basiert auf dem dynamischen Typ von k.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
146
5. Abstrakte Klassen
Abstrakte Methoden
Abstrakte Methoden in UML
Im UML-Klassendiagramm werden abstrakte Methoden durch eine kursive Schreibweise gekennzeichnet.
Vogel
+ singe()
Amsel
Drossel
Fink
+ singe()
+ singe()
+ singe()
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
147
5. Abstrakte Klassen
Abstrakte Methoden
Zusammenspiel: Abstrakte Klassen und Methoden
• Abstrakte Klassen dürfen abstrakte Methoden anbieten.
• Jede Klasse, die mindestens eine (evtl. geerbte) abstrakte Methode hat, ist selbst
abstrakt und muss entsprechend deklariert werden.
• Damit eine Unterklasse einer abstrakten Klasse eine konkrete Klasse werden
kann, muss sie Implementierungen für alle geerbten abstrakten Methoden anbieten.
• Andernfalls ist die Unterklasse selbst abstrakt und muss als solche gekennzeichnet
werden.
Damit haben wir Problem (2) gelöst:
• Wenn der Programmierer der Klasse Star vergessen sollte, die Methode
singe() zu überschreiben, meldet der Compiler einen Fehler.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
148
5. Abstrakte Klassen
Abstrakte Methoden
Wann setzt man abstrakte Klassen ein?
•
•
•
•
Zur Repräsentation einer Generalisierung verschiedener Klassen,
die Eigenschaften der gleichen Art haben,
die in den Unterklassen aber unterschiedlich berechnet werden müssen.
Für die Berechnung der Eigenschaften sehen wir in der Generalisierung jeweils
eine abstrakte Methode vor, um deutlich zu machen, dass Objekte dieser Klasse
(und der Unterklasse) diese Eigenschaften haben.
• Die jeweilige Art und Weise der Berechnung wird aber erst in den Unterklassen
festgelegt.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
149
5. Abstrakte Klassen
Weitere Beispiele
Beispiel: Roboter mit spezialisiertem Verhalten
• Übungsaufgabe der kommenden Woche.
• Roboter mit Positionsbestimmung in ganzzahligem Koordinatensystem
• Steuerungsmöglichkeiten für solche Roboter: Einen Schritt in aktuelle Richtung,
Änderung der Richtung durch Drehung um 90 Grad nach links bzw. rechts.
• In Unterklassen soll für die Roboterklassen ein spezifisches Verhalten festgelegt
werden: Sie erhalten einen Auftrag.
• Zugehörige Methode: bewegeDich()
• Torkelnder Roboter: Ziellos, zufällige Schritte und Drehungen
• Wächter: Geht ein vorgegebenes Rechteck ab.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
150
5. Abstrakte Klassen
Weitere Beispiele
Beispiel: Roboter mit spezialisiertem Verhalten (2)
Roboter
int gibX()
int gibY()
void macheSchritt()
void dreheLinks()
void dreheRechts()
void bewegeDich()
TorkelnderRoboter
void bewegeDich()
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
WächterRoboter
void bewegeDich()
151
5. Abstrakte Klassen
Weitere Beispiele
Beispiel: Geometrische Objekte und deren Eigenschaft Fläche
GeoObjekt
double x
double y
double gibX()
double gibY()
void verschiebe(double,double)
double berechneFlaeche()
Rechteck
Kreis
double breite
double hoehe
double radius
double berechneFlaeche()
double berechneFlaeche()
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
152
5. Abstrakte Klassen
Weitere Beispiele
Beispiel: Geometrische Objekte und deren Eigenschaft Fläche (2)
public abstract class GeoObjekt {
private double x;
private double y;
public GeoObjekt(double x, double y) {
this.x = x;
this.y = y;
}
...
public abstract double berechneFlaeche();
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
153
5. Abstrakte Klassen
Weitere Beispiele
Beispiel: Geometrische Objekte und deren Eigenschaft Fläche (2)
public class Rechteck extends GeoObjekt {
private double hoehe;
private double breite;
public Rechteck(double x, double y, double hoehe, double breite) {
super(x,y);
this.hoehe = hoehe;
this.breite = breite;
}
public double berechneFlaeche() {
return this.hoehe*this.breite;
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
154
5. Abstrakte Klassen
Weitere Beispiele
Beispiel: Geometrische Objekte und deren Eigenschaft Fläche (3)
public class Kreis extends GeoObjekt {
private double radius;
public Kreis(double x, double y, double radius) {
super(x,y);
this.radius = radius;
}
public double berechneFlaeche() {
return Math.PI * this.radius * this.radius;
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
155
6. Exceptions
Prinzipien von Exceptions
6. Exceptions
Hintergrund: Programmieren auf der Basis von Verträgen
Kundenklasse
Lieferantenklasse
Methodenaufruf
Methodendefinition
• Verpflichtung zur Einhaltung der
Vorbedingung
• Vorbedingung
• Invarianten
• Verpflichtung zur Einhaltung der
Nachbedingung
☞ Ausnahme: Lieferantenklasse kann ihren Vertrag nicht erfüllen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
156
6. Exceptions
Prinzipien von Exceptions
Beispiel:
public static void main(String[] args)
{
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
System.out.println(a + "/" + b + "=" + (a/b));
}
• java ExceptionTest
☞ ArrayIndexOutOfBoundsException
• java ExceptionTest 4 0
☞ ArithmeticException
• java Exception 4 a
☞ NumberFormatException
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
157
6. Exceptions
Prinzipien von Exceptions
Exception
• Eine Exception ist ein Objekt, das Informationen über einen Programmfehler
enthält.
• Eine Exception wird ausgelöst, um zu signalisieren, daß ein Fehler aufgetreten ist.
Vorteile von Exceptions:
• Für einen Klienten/Kunden ist es (fast) unmöglich, eine aufgetretene Exception zu
ignorieren und einfach weiterzuarbeiten.
• Wenn der Kunde die Exception nicht behandelt, dann wird die laufende Anwendung beendet.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
158
6. Exceptions
Prinzipien von Exceptions
Die Klasse java.lang.Exception
• Exceptions sind Instanzen der Klasse java.lang.Exception
• bzw. einer Unterklasse von java.lang.Exception.
• java.lang.Exception definiert die folgenden Methoden:
– getMessage(): Rückgabe der Fehlermeldung
– printStackTrace(): Erzeugt die Ausgabe, die wir auf der Konsole sehen.
Klassenname
Fehlermeldung
java.lang.ArithmeticException: / by zero
at ExceptionTest.main(ExectionTest.java:8)
Ort des Auftretens
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
159
6. Exceptions
Prinzipien von Exceptions
Exception-Klassen
• Eine Exception ist immer eine Instanz
aus einer speziellen Vererbungshierarchie.
• Wir können selbst neue ExceptionTypen definieren, indem wir Subklassen dieser Hierarchie erzeugen.
• Subklassen von java.lang.Error
sind für Fehler des Laufzeitsystems
vorgesehen.
• Für
neue
Exceptions
erzeugen
wir
Subklassen
von
java.lang.Exception.
• Das Paket java.lang stellt bereits
eine Reihe von vordefinierten Subklassen bereit.
Throwable
Error
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
Exception
GeprüfteException
RuntimeException
UngeprüfteException
160
6. Exceptions
Prinzipien von Exceptions
Arten von Exceptions
• Java unterscheidet zwischen geprüften und ungeprüften Exceptions.
• RuntimeException und alle Subklassen der Klasse RuntimeException definieren ungeprüfte Exceptions.
• Alle anderen Subklassen von Exception definieren geprüfte Exceptions
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
161
6. Exceptions
Prinzipien von Exceptions
Ungeprüfte Exceptions
• Dies sind Exceptions, bei deren Verwendung der Compiler keine zusätzlichen
Überprüfungen vornimmt.
• Genauer: Der Compiler prüft nicht, ob sich der Klient um diese Exceptions
kümmert.
• Ungeprüfte Exceptions sind für Fälle gedacht, die normalerweise nicht auftreten
sollten, z.B. ausgelöst durch Programmfehler.
Beispiele:
ArrayIndexOutOfBoundsException
NullPointerException
NumberFormatException
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
162
6. Exceptions
Prinzipien von Exceptions
Geprüfte Exceptions
• Geprüfte Exceptions sind Exception-Typen, bei deren Verwendung der Compiler
zusätzliche Überprüfungen durchführt und einfordert.
• Ein Klient muß sich um geprüfte Exceptions kümmern.
• Geprüfte Exceptions sind für die Fälle gedacht, bei denen ein Klient damit rechnen
sollte, daß eine Operation fehlschlagen kann. Hier sollte der Klient gezwungen
werden, sich um den Fehler zu kümmern.
Beispiele:
java.io.IOException, java.io.FileNotFoundException
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
163
6. Exceptions
Prinzipien von Exceptions
Faustregeln
Verwende ungeprüfte Exceptions ...
☞ ... in Situationen, die zu einem Programmabbruch führen sollten.
☞ ... bei Fehlern, die vermeidbar gewesen wären.
Verwende geprüfte Exceptions ...
☞ ... bei Fehlern, die vom Klienten behandelt werden können.
☞ ... für Fälle, die außerhalb des Einflusses des Programmierers liegen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
164
6. Exceptions
Behandlung von Exceptions
Auswirkungen einer Exception
• Wenn eine Exception ausgelöst wird, wird die Ausführung der auslösenden Methode sofort beendet.
• In diesem Fall muß kein Wert von der Methode zurückgeliefert werden, auch wenn
die Methode nicht als void deklariert wurde.
• Die Anweisung, die die auslösende Methode aufgerufen hat, konnte nicht korrekt
abgearbeitet werden.
• Es besteht die Möglichkeit, solche Exceptions zu fangen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
165
6. Exceptions
Behandlung von Exceptions
Kontrollfluß bei Exceptions
Klasse obj = new Klasse();
try {
. . .
obj.method();
. . .
}
catch ( MeineException e ) {
/* spez. F.-Behandlung */
}
catch ( Exception e ) {
/* allg. F.-Behandlung */
}
finally {
/* Aufräumarbeiten */
}
public class Klasse
{
public void method()
throws MeineException
{
. . .
/* Fehlererkennung */
throw new MeineException("...");
. . .
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
166
6. Exceptions
Behandlung von Exceptions
Die Konstrukte try, catch, finally, throw und throws
try
Definiert einen Block, innerhalb dessen Exceptions auftreten können.
catch
Definiert einen Block, der die Fehlerbehandlung für eine Ausnahme durchführt.
finally
Definiert einen Block, der Aufräumarbeiten durchführt.
throw
Erzeugt eine Ausnahme.
throws
Deklariert eine Ausnahme für eine Methode.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
167
6. Exceptions
Behandlung von Exceptions
Geprüfte Exceptions: throws
• Der Compiler fordert, daß eine Methode, die eine geprüfte Exception auslösen
(oder weiterreichen) kann, dies im Methodenkopf angibt.
• Syntaxbeispiel:
public void speichereInDatei(String dateiname)
throws IOException
• Die Angabe von ungeprüften Exception-Typen ist erlaubt aber nicht erforderlich.
• Hinter throws können durch Komma getrennt auch mehrere Exception-Typen angegeben werden.
public void kopiereDatei(String quelldatei, String zieldatei)
throws FileNotFoundException, IOException
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
168
6. Exceptions
Behandlung von Exceptions
Exception-Handler
• Ein Exception-Handler ist ein Programmabschnitt, der Anweisungen schützt, in denen eine Exception auftreten könnte.
• Der Exception-Handler definiert Anweisungen zur Meldung oder zum Wiederaufsetzen nach einer aufgetretenen Exception.
Syntax:
try {
geschützte Anweisungen
}
catch (ExceptionTyp e) {
Anweisungen für die Behandlung
}
finally {
Anweisungen für alle Fälle
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
169
6. Exceptions
Behandlung von Exceptions
Zwang zur Behandlung von Exceptions
• Eine Anweisung innerhalb der Methode caller ruft eine Methode method auf, die
eine Exception E auslösen kann.
• Dann muss für caller folgendes gelten:
Entweder in caller wird E durch einen Exception-Handler behandelt
oder caller macht mittels throws deutlich, daß die Exception E weitergereicht
wird.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
170
6. Exceptions
Behandlung von Exceptions
Propagierung von Exceptions
• Eine ausgelöste Exception wird entlang der Aufrufhierarchie propagiert, bis ein
geeigneter Exception-Handler gefunden wurde.
• Ein Exception-Handler ist geeignet, wenn er eine catch-Klausel hat, deren
Exception-Typ gleich E ist oder ein Obertyp davon.
• Die catch-Klauseln werden daraufhin in der Reihenfolge geprüft, wie sie im Quelltext angegeben sind.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
171
6. Exceptions
Behandlung von Exceptions
Auswahl des catch-Blocks
☞ Die erste passende catch-Klausel wird genommen!
falsch:
try {
...
}
catch (Exception e)
{
...
}
catch (SpezielleException se)
{
...
}
richtig:
try {
...
}
catch (SpezielleException se)
{
...
}
catch (Exception e)
{
...
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
172
6. Exceptions
Behandlung von Exceptions
Aufräumen mit finally
• Nach einer oder mehreren catch-Klauseln kann optional eine finally-Klausel
folgen.
• Die Anweisungen im Block zu finally werden immer ausgeführt:
– Wenn keine Exception ausgelöst wurde,
– wenn eine Exception ausgelöst und durch eine catch-Klausel behandelt wird
und auch
– wenn eine Exception ausgelöst wird, für die keine passende catch-Klausel vorhanden ist.
• Typische Anwendung: Freigabe von Ressourcen unabhängig vom Auftreten eines
Fehlers.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
173
6. Exceptions
Behandlung von Exceptions
Auslösen von Exceptions: throw
•
•
•
•
Exceptions werden mit Hilfe der throw-Klausel ausgelöst.
Hinter throw gibt man ein Exception-Objekt an.
Typischerweise erzeugt man hierzu ein neues Exception-Objekt mittels new.
Als Konstruktorparameter ist eine Fehlermeldung zulässig.
Beispiel:
throw new Exception("Parameterwert ungueltig!");
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
174
6. Exceptions
Exceptions und Vererbung
Maßgeschneiderte Exceptions
public class MyException extends Exception
{
...
public MyException() {
super();
}
public MyException(String msg) {
super( msg );
}
...
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
175
6. Exceptions
Exceptions und Vererbung
Exceptions und Vererbung
Klasse
Exception
public void method()
throws IOException;
Unterklasse
public void method()
IOException
OtherException
throws IOException,
OtherException;
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
176
6. Exceptions
Exceptions und Vererbung
Exceptions und Vererbung (2)
• Durch die throws-Klausel werden Exceptions Bestandteil des Vertrages zwischen
Klient und Lieferant.
• Sie regeln, was im Falle einer Vertragsverletzung passiert.
☞ Prinzip der Ersetzbarkeit: Spezialisierte Methoden dürfen keine neuen Exceptions
definieren.
• Konsequenz: Das Design der vorangegangenen Folie ist in Java nicht erlaubt!
• Korrekte Lösung: method() der Unterklasse darf nur IOException auslösen.
• Und wenn method() der Unterklasse andere Methoden benutzt, die andere Exceptions als IOException auslösen können?
Dann muss method() der Unterklasse diese Exceptions fangen und auf
IOException umsetzen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
177
6. Exceptions
Assertions
Assertions
• Seit Java 1.4 gibt es in Java das Konzept der Zusicherung (assertion).
• Eine Zusicherung ist ein Ausdruck, mit dem Einschränkungen definiert werden,
welche die erlaubten Zustände oder das Verhalten von Objekten betreffen.
• Zusicherungen gehören eigentlich zur Spezifikation bzw. Modellierung.
• Zusicherungen im Quelltext prüfen, ob die Spezifikation verletzt ist (Korrektheit).
• Verletzte Zusicherungen lösen in Java ein Objekt vom Typ AssertionError aus
(Untertyp von Error).
• Eine verletzte Zusicherung heißt: Das Programm bzw. die Klasse erfüllt nicht die
geforderte Spezifikation.
• Man beachte: Error statt Exception!
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
178
6. Exceptions
Assertions
Zusicherungen im Quelltext
• Die Überprüfung erfolgt mit dem Schlüsselwort assert:
assert boolscher-Ausdruck;
• Liefert der boolesche Ausdruck den Wert true, wird das Programm fortgesetzt.
• Ansonsten wird ein AssertionError ausgelöst.
• Optional kann für eine Assertion ein Fehlertext angegeben werden:
assert boolscher-Ausdruck : String-Ausdruck;
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
179
6. Exceptions
Assertions
Zusicherungen compilieren und aktivieren
• Sie benötigen eine Java-Version ≥ 1.4.
• Damit Kompatibilität zu älteren Versionen gewahrt ist, müssen Assertions für den
Compiler durch die Option -source aktiviert werden:
javac -source 1.4 Klasse.java
• Assertions sind auch in der virtuellen Maschine standardmäßig nicht aktiviert. Mit
Hilfe der Option -ea werden die Assertions aktiviert.
java -ea Klasse
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
180
7. Schnittstellen
Grundlagen zu Schnittstellen
7. Schnittstellen
Eine Schnittstelle (Interface) ist eine Spezifikation eines Typs in Form eines Typnamens und einer Menge von Methoden, die keine Implementierungen für die Methoden
definiert.
• Wir können Schnittstellen anschaulich zunächst als rein abstrakte Klassen auffassen, d.h. alle Methoden dieser Klasse sind abstrakt.
Was bringt uns das?
• Vollständige Trennung von Spezifikation und Implementierung
• Verschiedene Implementierungen der gleichen Spezifikation
• Austauschbarkeit
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
181
7. Schnittstellen
Grundlagen zu Schnittstellen
Beispiel CD-Spieler: Exemplare eines abstrakten Konzepts
Spezifikation
☞ einheitliche Signatur
☞ vereinbartes Verhalten
Datenabstraktion
☞ Trennung von Verhalten und Implementierung
☞ Verstecken der Implementierung
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
182
7. Schnittstellen
Grundlagen zu Schnittstellen
Schnittstelle: Syntax
Definition einer öffentlichen Schnittstelle:
public interface InterfaceName {
Konstantendeklarationen
Methodenköpfe
}
Beispiel:
public interface BewegbaresDing {
void bewegeDich();
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
183
7. Schnittstellen
Grundlagen zu Schnittstellen
Weitere Beispiele
public interface Funktion {
boolean istImDefBereich(double x);
double wert(double x);
String gibBeschreibung();
}
public interface Woerterbuch {
void put(String key, String info);
String get(String key);
void remove(String key);
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
184
7. Schnittstellen
Grundlagen zu Schnittstellen
Eigenschaften von Schnittstellendefinitionen
• Im Kopf wird statt class das Schlüsselwort interface verwendet.
• Alle Methoden in einem Interface sind abstrakt:
– es sind keine Methodenrümpfe zugelassen,
– das Schlüsselwort abstract wird nicht angegeben.
• Interfaces enthalten keine Konstruktoren.
• Alle Methoden sind implizit public:
– die Sichtbarkeit muss nicht angegeben werden.
• Als Datenfelder können nur öffentliche Konstanten deklariert werden:
– die Festlegung als Konstante durch public, static und final muss nicht
erfolgen.
Sichtbarkeit für Interfaces: nur public oder default ist möglich
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
185
7. Schnittstellen
Grundlagen zu Schnittstellen
Schnittstellen und Datentypen (1)
• Wenn die Schnittstellendefinition in einer Datei mit der Endung .java liegt, können
wir die Schnittstellendefinition wie eine Klasse übersetzen.
• Analog zu einer Klasse entsteht durch die Kompilierung auch eine .class-Datei.
• Ebenso wie bei Klassen ist mit jeder Schnittstelle auch ein Datentyp verbunden.
• Da Schnittstellen aber abstrakt sind, können zu Schnittstellen nicht direkt Objekte
erzeugt werden, d.h.
new Schnittstelle(...);
ist nicht möglich.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
186
7. Schnittstellen
Grundlagen zu Schnittstellen
Implementierung von Interfaces
• Klassen können Interfaces implementieren.
• Hierzu müssen unsere Klassen folgendes leisten:
1. Für jede Methode des Interfaces muss die Klasse eine Methode mit passender
Signatur anbieten.
2. Im Kopf der Klasse müssen wir explizit angegeben, dass unsere Klasse das
Interface implementiert. Hierzu nutzen wir das Schlüsselwort implements.
Syntax:
public class Klasse extends Oberklasse implements Schnittstelle {
...
}
Beispiele: ☞ Funktionen
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
187
7. Schnittstellen
Grundlagen zu Schnittstellen
Implementierung mehrerer Interfaces
• Wenn wir extends zusammen mit implements nutzen, muss extends vor
implements stehen.
• Es ist möglich, dass eine Klasse mehr als eine Schnittstelle implementiert.
• In diesem Fall geben wir alle implementierten Schnittstellen als Kommaliste hinter
implements an.
public class Klasse extends Oberklasse
implements Schnittstelle1, Schnittstelle2, ...
{
...
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
188
7. Schnittstellen
Einsatz von Interfaces
Schnittstellen und Datentypen (2)
• Ein Interface definiert genau wie eine Klasse einen Datentyp.
• Klassen, die ein Interface implementieren, definieren Subtypen des Interface-Typs.
• Somit können Variablen von einem Interface-Typ deklariert werden, obwohl keine
Objekte dieses Typs existieren können, sondern nur Objekte der Subtypen.
• Wenn die Klasse Parabel die Schnittstelle Funktion implementiert:
Funktion f = new Parabel( 1.0, 0.0, 0.0 );
• Auch möglich:
Funktion[] f = new Funktion[10];
• Damit haben wir wieder Variablen- und Methodenpolymorphie.
Beispiel: ☞ Funktionen
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
189
7. Schnittstellen
Einsatz von Interfaces
Schnittstellen und Vererbung
• Schnittstellen besitzen analog zu Klassen die Möglichkeit, mit dem Schlüsselwort
extends eine schon vorhandene Schnittstelle zu erweitern.
• public interface NachrichtenQuelle {
public int SPORT
= 0;
public int POLITIK = 1;
public int KULTUR
= 2;
public int ANZEIGEN = 3;
public int GESAMT
= 4;
public void anmelden(NachrichtenEmpfaenger empf, int typ);
public void sendeNachricht(String nachricht);
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
190
7. Schnittstellen
Einsatz von Interfaces
• public interface Vermittler extends NachrichtenQuelle {
public void empfangeNachricht(String nachricht);
}
• Wirkungsweise: Die Definition der Unterschnittstelle erbt die Definitionen der Oberschnittstelle.
• Hierbei muss wieder das Prinzip der Ersetzbarkeit gewährleistet bleiben.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
191
7. Schnittstellen
Einsatz von Interfaces
Mehrfachvererbung bei Schnittstellen
• Im Gegensatz zur Einfachvererbung von Klassen ist in Java bei Schnittstellen eine
Mehrfachvererbung erlaubt.
• Damit kann eine Schnittstelle gleichzeitig mehrere andere Schnittstellen erweitern.
• public interface Schnittstelle
extends Oberschnittstelle1, Oberschnittstelle2, ... {
...
}
• Die Mehrfachvererbung bei Schnittstellen hat allerdings keine große Bedeutung.
Die Möglichkeit, dass eine Klasse mehrere Schnittstellen implementiert, ist von
erheblich größerer Bedeutung.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
192
7. Schnittstellen
Einsatz von Interfaces
Mehrdeutigkeiten bei Mehrfachvererbung
public interface Grundfarben {
int ROT = 1; int GRUEN = 2;
int BLAU = 3;
}
public interface Sockenfarben
extends Grundfarben {
int SCHWARZ = 10; int LILA = 11;
}
public interface Hosenfarben
extends Grundfarben {
int LILA = 11; int SCHWARZ = 20;
int BRAUN = 21;
}
public interface Allefarben
extends Sockenfarben, Hosenfarben {
int BRAUN = 30;
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
193
7. Schnittstellen
Einsatz von Interfaces
• Konstanten werden vererbt: Allefarben.ROT
• Konstanten dürfen überschrieben werden: Allefarben.BRAUN
• Bei der Nutzung der Konstanten dürfen keine Mehrdeutigkeiten auftreten:
Allefarben.SCHWARZ
• Auch keine potentiellen Mehrdeutigkeiten: Allefarben.LILA
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
194
7. Schnittstellen
Einsatz von Interfaces
Typumwandlungen (Upcasting)
Implizite Upcasts finden in folgenden Fällen statt:
• Von Klasse U nach Klasse O , wenn U Unterklasse von O ist.
• Von Klasse K nach Schnittstelle S, wenn die Klasse K die Schnittstelle S implementiert.
• Von null zu jeder Klasse, Schnittstelle oder Feld.
• Von Schnittstelle U nach Schnittstelle S, wenn U Unterschnittstelle von S ist.
• Von Schnittstelle oder Feld zu Object.
• Von Feld S[ ] mit Schnittstelle S als Komponententyp nach Feld T[ ] mit Typ T als
Komponententyp, wenn es einen Upcast von S nach T gibt.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
195
7. Schnittstellen
Einsatz von Interfaces
Typumwandlungen (Downcasting)
•
•
•
•
Die Verwendung von instanceof ist auch mit Schnittstellentypen möglich.
Downcasting ist nur explizit möglich.
Wird zur Laufzeit auf Korrektheit geprüft.
ClassCastException falls Downcasting fehlerhaft
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
196
7. Schnittstellen
Einsatz von Interfaces
Schnittstellen und Exceptions
Zur Schnittstellendefinition gehört auch die Deklaration von möglichen Exceptions.
Folgende Konstruktion ist nicht erlaubt:
interface Schnittstelle {
void methode();
}
public class Klasse implements Schnittstelle {
public void methode() throws Exception { ... }
}
☞ Widerspruch zum Prinzip der Ersetzbarkeit.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
197
7. Schnittstellen
Einsatz von Interfaces
Lösung: Die Exception muss in der Schnittstelle deklariert werden!
interface Schnittstelle {
void methode() throws Exception;
}
• Damit dürfte die Implementierung von methode() Exception oder eine beliebige
Unterklasse von Exception auslösen.
• Nicht gestattet: allgemeinere Exceptions oder weitere Exceptions
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
198
7. Schnittstellen
Einsatz von Interfaces
Beispiel: CharSequence
Siehe: C. Ullenboom, Java ist auch eine Insel, Abschnitt 6.10.7
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
199
7. Schnittstellen
Einsatz von Interfaces
Interfaces als Spezifikation
• Interfaces erlauben es, die Funktionalität (Schnittstelle) vollständig von der Implementierung zu trennen.
• Gute Beispiele hierfür findet man im Java SDK.
• Im Paket java.util findet man beispielsweise das Interface List sowie die Klassen ArrayList und LinkedList.
• Das Interface List definiert die volle Funktionalität einer Liste, ohne eine Implementierung festzulegen.
• Die Klassen ArrayList und LinkedList stellen verschiedene Implementierungen dieser Schnittstelle dar.
• Die beiden Implementierungen unterscheiden sich erheblich in der Effizienz einiger
Methoden.
• Welche Implementierung für eine gegebene Anwendung besser ist, ist im voraus
oft schwer festzulegen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
200
7. Schnittstellen
Einsatz von Interfaces
• Das Interface List macht aber solch eine Listenanwendung flexibel.
• Wenn wir stets List für Datentypen bei den entsprechenden Variablen und Parametern verwenden, funktioniert die Anwendung unabhängig von der aktuell
gewählten Implementierung für Listen.
• Lediglich bei der Erzeugung einer Liste müssen wir eine Implementierung festlegen. Beispiel:
private Liste meineListe = new ArrayList();
• So könnten wir in der Anwendung eine LinkedList verwenden, indem wir einfach
an dieser einen Stelle ArrayList durch LinkedList ersetzen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
201
7. Schnittstellen
Einsatz von Interfaces
Markierungsschnittstelle (Marker Interface)
• Eine Markierungsschnittstelle enthält in Ihrer Definition keine Methoden.
• Implementierende Klassen geben über eine Markierungsschnittstelle an, dass sie
eine bestimmte Funktionalität unterstützen.
• Beispiel: java.lang.Cloneable
• Objekte aus Klassen, die Cloneable nicht implementieren, können nicht kopiert
werden.
☞ CloneNotSupportedException
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
202
8. Parametrisierbare Klassen
Grundlagen
8. Parametrisierbare Klassen
Java now supports generics, the most significant change to the language since
the addition of inner classes in Java 1.2 — some would say the most significant
change to the language ever.
M. Naftalin, P. Wadler, Java Generics, O’Reilly, 2006.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
203
8. Parametrisierbare Klassen
Grundlagen
Beispiel: Stapel (Stack)
Wichtige abstrakte Datentypen bzw. Datenstrukturen der Informatik sind unabhängig
von einem Basis- bzw. Komponententyp.
Beispiel: Es sei T ein beliebiger Datentyp. Ein Stapel (Stack) unterstützt die folgenden Operationen:
• void push(T element)
Legt das Element e vom Typ T auf dem Stapel ab.
• T pop()
Entfernt das oberste Element vom Stapel und liefert es als Ergebnis zurück.
☞ Die Anweisungen zur Implementierung eines Stapels sind unabhängig vom Komponententyp T .
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
204
8. Parametrisierbare Klassen
Grundlagen
Generische Objektreferenz durch Object (1)
Zunächst kein Problem, es gibt ja die Klasse Object.
public class Stapel
{
...
void push(Object element) { ... }
Object pop() { ... }
...
}
☞ Vorgehensweise bis Java 1.4
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
205
8. Parametrisierbare Klassen
Java Generics
Generische Objektreferenz durch Object (2)
Probleme:
• Downcasting notwendig nach pop()
T t = (T) stack.pop();
• Keine Typüberprüfung zur Übersetzungszeit
Stack stack = new Stack();
stack.push( new Integer(4711) ); // wird vom Compiler
stack.push( "hallo!" );
// anstandslos akzeptiert
• Evtl. Typfehler zur Laufzeit
Integer i = (Integer) stack.pop(); // ClassCastException
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
206
8. Parametrisierbare Klassen
Java Generics
Generische Objektreferenz durch Object (3)
Und wenn wir für jeden benötigten Komponententyp eine eigene Implementierung
bereitstellen?
• hoher Aufwand
– Mehrfache Verwendung des fast gleichen Quelltextes
– Mehrfaches Testen notwendig
– entdeckte Fehler müssen mehrfach korrigiert werden
• geringe Abstraktion
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
207
8. Parametrisierbare Klassen
Java Generics
Typvariablen
• Seit Java 5 sind Typvariablen bei einer Klassendefinition möglich.
• Die damit realisierte Klasse entspricht einem generischen Datentyp.
• In der objektorientierten Programmierung bezeichnen wir dies auch als parametrische Polymorphie.
• In Java bezeichnet man diese Möglichkeit als Generics.
Beispiel:
class Stapel<T>
{
...
void push(T element) { ... }
T pop() { ... }
...
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
208
8. Parametrisierbare Klassen
Java Generics
Die Typvariable T ersetzt innerhalb der Klassendefinition einen konkreten Typ.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
209
8. Parametrisierbare Klassen
Java Generics
Nutzung generischer Typen (1)
Für die Instanziierung müssen wir die Typvariable durch einen konkreten Typ ersetzen.
Stapel<String> sstapel = new Stapel<String>();
Stapel<Double> dstapel = new Stapel<Double>();
Die Stapel sind typsicher:
dstapel.push("text");
// hier meckert der Compiler
Kein Downcasting notwendig:
Double d = dstapel.pop();
// kein Problem
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
210
8. Parametrisierbare Klassen
Java Generics
Nutzung generischer Typen (2)
Leider wäre die folgende Deklaration nicht erlaubt:
Stapel<int> istapel = new Stapel<int>();
Grund: Typvariablen dürfen nur durch Referenztypen instanziiert werden.
Wie können wir denn dann einen Integer-Stapel erzeugen? Verwendung von WrapperKlassen: Integer, Double, etc.
Stapel<Integer> istapel = new Stapel<Integer>();
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
211
8. Parametrisierbare Klassen
Java Generics
Exkurs: Wrapper-Klassen (Hüllklassen)
• Instanzen von Wrapper-Klassen (Hüllklassen) haben die Aufgabe, einen primitiven
Wert als Objekt zu repräsentieren.
• Es gibt für jeden einfachen Datentyp eine zugehörige Wrapper-Klasse, z.B.
int/Integer, double/Double, char/Character.
• Integer i = new Integer(4711);
• Wie Strings sind Instanzen von Wrapper-Klassen grundsätzlich unveränderlich (immutable).
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
212
8. Parametrisierbare Klassen
Java Generics
Exkurs: Boxing und Unboxing
• Die Repräsentation eines einfachen Wertes als Objekt mit Hilfe einer WrapperKlasse bezeichnen wir auch als Boxing.
Integer io = new Integer(4711); // Boxing
• Der Zugriff auf den einfachen Wert nennen wir Unboxing.
int ival = io.intValue(); // Unboxing
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
213
8. Parametrisierbare Klassen
Java Generics
Exkurs: Autoboxing (1)
• Die manuelle Ausführung von Boxing und Unboxing ist oft unhandlich.
Stapel<Integer> istapel = new Stapel<Integer>();
istapel.push( new Integer(4711) );
int iv = istapel.pop().intValue();
• Die automatische Umwandlung von Werten einfacher Datentypen in Instanzen einer Wrapper-Klasse und umgekehrt wird als Autoboxing bezeichnet.
• Java beherrscht Autoboxing seit Java 5.
int i
= 4711;
Integer j = i;
int k
= j;
// automatisches Boxing
// automatisches Unboxing
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
214
8. Parametrisierbare Klassen
Java Generics
Exkurs: Autoboxing (2)
Damit ist natürlich auch möglich:
Stapel<Integer> istapel = new Stapel<Integer>();
istapel.push(4711);
// Boxing
int iv = istapel.pop();
// Unboxing
Vorsicht bei Vergleichen mit == und Autoboxing!
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
215
8. Parametrisierbare Klassen
Java Generics
Typanpassungen
Ein instanziierter generischer Typ lässt sich durch Typanpassung auf eine allgemeine
Form bringen:
Stapel<Integer> istapel = new Stapel<Integer>();
Stapel
stapel = (Stapel) istapel;
Jetzt findet für stapel keine Typprüfung mehr statt. Daher würde
stapel.push("No Integer");
keinen Fehler zur Übersetzungszeit liefern.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
216
8. Parametrisierbare Klassen
Java Generics
Typvariablen in Methoden
Typvariablen können auch auf Methodendeklarationen beschränkt sein:
class Util
{
public static <T> T zufall(T o1, T o2)
{
return Math.random() > 0.5 ? o1 : o2;
}
}
Die Angabe von <T> beim Klassennamen entfällt und verschiebt sich auf die Methodendefinition.
☞ Typinferenz
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
217
8. Parametrisierbare Klassen
Realisierung von Generics
Realisierung von Generics
• heterogen
Für jeden konkreten Typ wird individueller Code erzeugt.
Diesen Ansatz verfolgt z.B. C++ (templates directory)
• homogen
kein individueller Code, Object statt der Typvariablen, Typanpassungen für einen
konkreten Typ, Typüberprüfungen zur Übersetzungszeit
Realisierung für Java
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
218
8. Parametrisierbare Klassen
Realisierung von Generics
Typlöschung
Zur Laufzeit ist der konkrete Typ der Typvariablen nicht bekannt. Dies hat Konsequenzen für instanceof.
Folgendes liefert einen Übersetzungsfehler:
Stapel<String> stapel = new Stapel<String>();
if ( stapel instanceof Stapel<String> ) //
...
Grund: Zur Laufzeit liegt nur die Typinformation Stapel vor.
Stapel<String> stapel1 = new Stapel<String>();
Stapel<Integer> stapel2 = new Stapel<Integer>();
System.out.println(stapel1.getClass() == stapel2.getClass()); // true!
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
219
8. Parametrisierbare Klassen
Realisierung von Generics
Raw-Type
Eine Instanziierung mit einem konkreten Typ muss nicht unbedingt stattfinden. Ohne
Instanziierung gilt implizit Object als konkreter Typ.
Stapel stapel = new Stapel<String>();
Stapel ostapel = new Stapel();
Solche Typen heissen Raw-Type.
Raw-Typen können wir die parametrisierten Typen verwendet werden. Es findet aber
keine Typüberprüfung statt.
Eventuell gibt der Compiler Warnungen aus.
☞ Vorsicht vor Typroblemen zur Laufzeit.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
220
8. Parametrisierbare Klassen
Typeinschränkungen bei Generics
Typeinschränkungen bei Generics
Die zugelassenen konkreten Datentypen können mit extends auf Untertypen eines
Obertyp eingeschränkt werden.
Beispiel: Ein typsicheres generisches max:
public static <T extends Comparable> T max(T o1, T o2)
{
return o1.compareTo(o2) > 0 ? o1 : o2;
}
☞ extends auch für Untertypen von Schnittstellen!
☞ Das ist besser als
public static Comparable max(Comparable o1, Comparable o2)
Warum?
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
221
8. Parametrisierbare Klassen
Typeinschränkungen bei Generics
Einschränkung mit super
• Mit super statt extends kann eine Einschränkung auf Obertypen statt auf Untertypen erfolgen.
• <T super O>
• Damit dürfen für die Typvariable T O oder Obertypen von O eingesetzt werden.
• Diese Einschränkung wird z.B genutzt, wenn eine mit T parametrisierte generische
Datenstruktur manipuliert wird (Kontravarianz).
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
222
8. Parametrisierbare Klassen
Typeinschränkungen bei Generics
Kombinationen von Obertypen
• Soll die Typvariable T zu mehreren Obertypen passen, lassen sich Kombinationen
bilden.
• Man beachte: Für T kann nur eine Oberklasse angegeben werden, da es in Java
nur einfache Vererbung bei Klassen gibt.
• Weitere Obertypen müssen Schnittstellen sein.
• <T extends O & I1 & I2 & ...>
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
223
8. Parametrisierbare Klassen
Typeinschränkungen bei Generics
Generics und Vererbung (1)
• Wenn Fussballer eine Unterklasse von Sportler ist, dann ist Fussballer[]
ein Untertyp von Sportler[].
• Daher ist folgenden problemlos möglich:
Fussballer[] fussballer = new Fussballer[11];
Sportler[] sportler = fussballer;
• In der objektorientierten Programmierung bezeichnet man dies als Kovarianz.
• Beispiel:
public static void gebeSportlerAus(Sportler[] sportler) {
for (int i=0 ; i<sportler.length ; i++)
sportler[i].gibAus();
}
Kovarianz stellt bei lesendem Zugriff kein Problem dar.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
224
8. Parametrisierbare Klassen
Typeinschränkungen bei Generics
Generics und Vererbung (2)
• Generics sind untereinander nicht kovariant sondern invariant!
• D.h. Stapel<Fussballer> ist kein Untertyp von Stapel<Sportler>.
• Daher liefert der Compiler für folgende Anweisungen einen Fehler:
Stapel<Sportler> sportler = new Stapel<Fussballer>();
• Begründung: Wenn erlaubt, dann wäre folgendes möglich:
sportler.push(new Handballer());
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
225
8. Parametrisierbare Klassen
Typeinschränkungen bei Generics
Generics und Vererbung (3)
• Kovarianz stellt bei schreibendem Zugriff ein Problem dar!
• Dagegen wäre folgendes vom Prinzip her unproblematisch:
Stapel<Sportler> sportler = new Stapel<Mensch>();
sportler.push(new Handballer());
sportler.push(new Sportler());
• Kontravarianz
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
226
8. Parametrisierbare Klassen
Typeinschränkungen bei Generics
Generische Variablen: Wildcards
Folgendes funktioniert nicht:
Stapel<Sportler> sportler;
Stapel<Fussballer> fussballer = new Stapel<Fussballer>();
Stapel<Handballer> handballer = new Stapel<Handballer>();
sportler = fussballer;
// Fehler!
• Es ist aber möglich, statt konkreter Typangaben Wildcards anzugeben.
• Diese können mit zusätzlichen Einschränkungen (extends, super) versehen
werden.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
227
8. Parametrisierbare Klassen
Typeinschränkungen bei Generics
Generische Variablen: Wildcards (2)
Beispiel:
Stapel<? extends Sportler> sportler;
Stapel<Fussballer> fussballer = new Stapel<Fussballer>();
Stapel<Handballer> handballer = new Stapel<Handballer>();
Stapel<Biertrinker> biertrinker = new Stapel<Biertrinker>();
sportler = fussballer; sportler = handballer;
// OK!
sportler = biertrinker;
// Fehler!
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
228
8. Parametrisierbare Klassen
Typeinschränkungen bei Generics
Generische Variablen: Wildcards (3)
Wildcard mit extends liefert uns Kovarianz: Für
public static void gebeSportlerAus(Stapel<? extends Sportler> sportler) {
for (Sportler s : sportler) s.gibAus();
}
ist
Stapel<Fussballer> fussballer = new Stapel<Fussballer>();
gebeSportlerAus(fussballer);
kein Problem.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
229
9. Aufzählungen mit enum
Konstanten und Aufzählungen
9. Aufzählungen mit enum
Für die Definition von systemweiten Konstanten haben wir bisher öffentliche finale
Klassenvariablen verwendet.
public class MusicStyle {
public static final int
public static final int
public static final int
public static final int
}
ROCK
POP
COUNTRY
TECHNO
=
=
=
=
0;
1;
2;
3;
Probleme:
• Kein Zwang zur Verwendung
• Datentyp int statt eines eigenen Datentyps
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
230
9. Aufzählungen mit enum
enum
enum-Deklaration (1)
Seit Java 5 sind “richtige Aufzählungen” mit dem Schlüsselwort enum möglich.
Syntax:
public enum Aufzählungstyp {
Aufzählung
}
Beispiel:
public enum Wochentag {
MONTAG, DIENSTAG, ... , SONNTAG
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
231
9. Aufzählungen mit enum
enum
enum-Deklaration (2)
• Eine enum-Deklaration verhält sich wie eine Klassendeklaration.
• Insbesondere ist mit der Deklaration ein neuer Datentyp verbunden.
Wochentag tag = Wochentag.SONNTAG;
•
•
•
•
Ober- und Unterklassen sind nicht erlaubt.
Variablen und Methoden sind möglich.
Für den Aufzählungstyp wird eine class-Datei erstellt.
Die Elemente der Aufzählung werden durch Objekte repräsentiert.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
232
9. Aufzählungen mit enum
enum
enum-Konstanten in switch
enum-Konstanten können als case-Marke verwendet werden.
Wochentag tag = Wochentag.SONNTAG;
switch (tag) {
case MONTAG :
System.out.println("Ich mag keine Montage!");
break;
case FREITAG:
System.out.println("Gott sei Dank, es ist Freitag!");
break;
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
233
9. Aufzählungen mit enum
enum
enum und Objektorientierung
• enum-Typen überschreiben sinnvoll die folgenden Methoden aus java.lang.Objects:
– toString()
– hashCode()
– equals()
• Sie implementieren die Schnittstellen Serializable und Comparable.
• Die Ordnung der Elemente ergibt sich durch die Reihenfolge bei der Deklaration.
• Aufzählungstypen sind Referenztypen! Daher ist
Wochentag tag = null;
möglich.
• Wo notwendig auf == null prüfen und Exception auslösen.
• import wie bei Klassen
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
234
9. Aufzählungen mit enum
enum
Praktische Methoden im Zusammenhang mit enum
• Die statische Methode valueOf(String) bestimmt zu einem String den zugehörigen enum-Wert:
Wochentag tag = Wochentag.valueOf("SONNTAG"); // liefert Wochentag.SONNTA
• Die Umkehrung hierzu ist toString():
Wochentag tag = Wochentag.valueOf("SONNTAG");
System.out.println("Heute ist " + tag.toString());
• Die Methode ordinal() liefert die Ordinalzahl zu einer enum-Konstanten.
• Die Klassenmethode values() liefert ein Feld mit allen Werten des Aufzählungstyps:
for (Wochentag t : Wochentag.values())
System.out.println(t + " hat den Wert " + t.ordinal());
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
235
10. Pakete
Grundlagen zu Paketen
10. Pakete
Ein Paket (package) bündelt thematisch zusammengehörige Klassen und Schnittstellen zu einer Klassenbibliothek.
Beispiele:
•
•
•
•
java.lang: Standardklassen zur Sprache Java
java.net: Klassen zur Netzwerkprogrammierung
java.io: Klassen für die Ein- und Ausgabe von Daten
java.awt: Klassen für graphische Oberflächen (Abstract Window Toolkit)
Pakete haben einen Namen, den Paketnamen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
236
10. Pakete
Grundlagen zu Paketen
Vorteile von Paketen
• Pakete bilden eigene Bereiche für die Sichtbarkeit. Dadurch kann mit Paketen eine
Datenkapselung erreicht werden.
• Jedes Paket bildet einen eigenen Namensraum. Damit können Namenskonflikte
vermieden werden und identische Namen für Klassen in verschiedenen Paketen
vergeben werden.
• Pakete sind gröbere Einheiten für die Strukturierung von objektorientierten Systemen als Klassen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
237
10. Pakete
Benutzung von Paketen
Nutzung von Klassen aus Paketen (1)
Für die Nutzung von Klassen aus Paketen gibt es zwei Möglichkeiten:
• volle Qualifikation: Paket und Klassenname werden angegeben:
java.awt.Point p = new java.awt.Point();
• Deklaration mit Hilfe von import: Es wird einmal angegeben, aus welchen Paketen Klassen importiert werden:
import java.awt.Point;
Point p = new Point();
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
238
10. Pakete
Benutzung von Paketen
Nutzung von Klassen aus Paketen (2)
Um nicht alle Klassen eines Paketes einzeln angeben zu müssen, besteht die Möglichkeit, mit Hilfe des * alle Klassen zu importieren.
Die Anweisung
import java.awt.*;
importiert alle Klassen aus dem Paket java.awt.
☞ import steht zwischen einer optionalen package-Deklaration und dem Rest des
Quelltextes.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
239
10. Pakete
Benutzung von Paketen
Nutzung von Klassen aus Paketen (3)
• Das Paket java.lang wird immer automatisch importiert.
• Sollten Klassen mit gleichem Namen aus verschiedenen Paketen importiert werden, muss eine volle Qualifikation erfolgen.
• Auch Pakete können hierarchisch strukturiert werden (Unterpakete).
• import bezieht die Unterpakete nicht automatisch mit ein!
import java.awt.*;
import java.awt.geom.*;
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
240
10. Pakete
Benutzung von Paketen
Statischer Import
Klassenmethoden bzw. Konstanten werden über den Methodennamen (bzw. Konstantennamen) in Verbindung mit dem Klassennamen angesprochen.
double x = Math.sin( Math.PI/4 );
Seit Java 5 können Klassenmethoden und Konstanten statisch importiert werden:
import static java.lang.Math.sin;
import static java.lang.Math.PI;
double x = sin( PI/4 );
Auch beim statischen Import ist der Einsatz von * möglich.
Ein statischer Import ist auch für überladene Klassenmethoden möglich.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
241
10. Pakete
Pakete selber bauen
Die package-Deklaration
• Mit Hilfe einer package-Deklaration können wir Quelltextteile Paketen zuordnen.
package Paketbezeichner;
• Die package-Deklaration muss vor allen anderen Anweisungen im Quelltext stehen.
• Hinter package wird ein hierarchisch aufgebauter Paketbezeichner als Paketname
angegeben.
package de.fhbrs.inf.meinPaket;
• Wirkung: Alle Klassen und Schnittstellendefinitionen der Übersetzungseinheit
(.java-Datei), werden dem Paket de.fhbrs.inf.meinPaket zugeordnet.
• Natürlich können auch andere .java-Dateien diesem Paket zugeordnet werden.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
242
10. Pakete
Pakete selber bauen
Paketnamen
•
•
•
•
Für die weltweite Eindeutigkeit: häufig umgedrehte Domainnamen
Für die hierarchische Strukturierung ist der Punkt erlaubt.
Dagegen ist leider kein “–” in Paketnamen erlaubt.
Die Paketnamen java, javax und sun sind reserviert.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
243
10. Pakete
Pakete selber bauen
Default-Package
Was passiert, wenn wir keine package-Deklaration angeben?
• Die Quelltextteile werden einem sogenannten Default-Package zugeordnet.
• Zu diesem Default-Package gehören alle Übersetzungseinheiten des lokalen Verzeichnisses, die nicht einem Paket zugeordnet sind.
• Daher müssen wir uns bei kleinen Anwendungen nicht um die Paketorganisation
kümmern.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
244
10. Pakete
Pakete selber bauen
Verzeichnisstruktur für Pakete
projekte
• In der Regel setzen wir für
die Entwicklung die Paketstruktur eins zu eins auf eine Dateistruktur um.
• Verzeichnisse tragen den
Paketnamen.
• Die zum Paket gehörigen
Klassen werden in den
entsprechenden Verzeichnissen abgelegt.
lib
paket1
sub1
Klasse1
projekt1
projekt2
classes
doc
paket2
Klasse2
sub2
Klasse3
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
245
10. Pakete
Pakete selber bauen
C LASSPATH
• Wenn sich nicht alle class-Dateien im lokalen Verzeichnis befinden, muss die
virtuelle Maschine wissen, wo sie nach class-Dateien suchen soll.
• Hierzu dient die Umgebungsvariable CLASSPATH.
• Genauer: Im C LASSPATH werden die Verzeichnisse aufgelistet, in denen nach Paketen gesucht wird.
• Mit
CLASSPATH=/projekte/projekt1/classes
werden die Klassen paket1.klasse1, paket1.klasse2 und auch paket1.sub1.klasse3
gefunden.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
246
10. Pakete
Pakete selber bauen
jar-Dateien
• Für die Auslieferung einer Klassenbiblothek ist es einfacher, wenn sich die gesamte Bibliothek in einer Datei befindet, statt in einer losen Sammlung von classDateien.
• Dies ist mit jar-Dateien möglich.
• Eine jar-Datei ist eine Zusammenstellung von Dateien in einer einzigen Datei.
• Erzeugung von jar-Dateien: siehe Hinweise auf der Homepage.
• jar-Dateien können im C LASSPATH verwendet werden.
• $ cd /projekte/projekt1/classes
$ jar cf ../lib/projekt1.jar paket1 paket2
$ CLASSPATH=/projekte/projekt1/lib/projekt1.jar
Damit werden die Klassen aus den Paketen paket1, paket2 und paket1.sub1
gefunden.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
247
10. Pakete
Zugriffsmodifikatoren und Zugriffsrechte
Verwendung von Zugriffsmodifikatoren
• Zur Regelung der Zugriffsrechte gibt es in Java die Modifikatoren public,
protected und private.
• Ohne Zugriffsmodifikator besteht das Zugriffsrecht default.
• Beachten Sie: default ist kein Schlüsselwort.
• Für Klassen sind die Zugriffsrechte public und default möglich.
• Für Klassen- bzw. Instanzvariablen und -methoden sind möglich: default,
public, protected und private.
• Variablen und Methoden innerhalb von Schnittstellen sind implizit public.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
248
10. Pakete
Zugriffsmodifikatoren und Zugriffsrechte
Zugriffsrechte für Variablen und Methoden
Klasse A
Klasse B
gleiches Paket
Subklasse C
gleiches Paket
Klasse D
anderes Paket
Subklasse E
anderes Paket
private
default
protected
public
ja
ja
ja
ja
nein
ja
ja
ja
nein
ja
ja
ja
nein
nein
nein
ja
nein
nein
ja/nein
ja
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
249
11. Java-Klassenbibliothek
Pakete des JDK
11. Java-Klassenbibliothek
Die Java-Bibliothek der Standard Edition umfasst:
•
•
•
•
•
•
•
mehr als 200 Pakete. Diese definieren
3777 Typen, davon
2457 Klassen,
972 Schnittstellen,
49 Aufzählungen,
473 Klassen für Exceptions und
32 Error-Klassen
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
250
11. Java-Klassenbibliothek
Wrapper-Klassen
Wrapper-Klassen
Wrapper-Klassen erfüllen zwei Aufgaben:
• Repräsentation eines Werts als Objekt (siehe Kapitel Generics)
• Sie stellen Methoden für die Umwandlung von Werten bereit.
Wrapper-Klasse
Byte
Short
Integer
Long
Double
Float
Boolean
Character
Void
Einfacher Datentyp
byte
short
int
long
double
float
boolean
char
void
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
251
11. Java-Klassenbibliothek
Wrapper-Klassen
Erzeugung von Wrapper-Objekten
• Die Objekte zu den einfachen Werten können durch einen Konstruktoraufruf erzeugt werden.
• Die Konstruktoren akzeptieren üblicherweise die zugehörigen einfachen Werte
oder Strings.
Integer
Double
String
Integer
i
d
s
i
=
=
=
=
new Integer( 4711 );
new Double( 0.815 );
"4711";
new Integer( s );
• Bei nicht korrekt aufgebauten Strings: NumberFormatException
• Weitere Methoden zur Erzeugung von Wrapper-Objekten: Klassenmethode
valueOf
Integer i = Integer.valueOf( 4711 );
String s = "4711";
Integer i = Integer.valueOf( s );
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
252
11. Java-Klassenbibliothek
Wrapper-Klassen
Zugriff auf den Wert
• Hängt ab von der Wrapper-Klasse,
• z.B. intValue für Integer, booleanValue für Boolean
• Zusätzlich wird Autoboxing unterstützt.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
253
11. Java-Klassenbibliothek
Zahlen mit beliebiger Genauigkeit
Zahlen mit beliebiger Genauigkeit
Die Datentypen int und double haben eine beschränkten Wertevorrat.
• Mit Hilfe der Klasse java.Math.BigInteger können wir beliebig große Zahlen
repräsentieren,
• mit Hilfe der Klasse java.Math.BigDecimal beliebiger vorgegebener Genauigkeit.
• Möglich ist dies durch eine variabel lange Repräsentation.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
254
11. Java-Klassenbibliothek
Zahlen mit beliebiger Genauigkeit
Konstruktoren und Methoden für BigInteger
• Am einfachsten erzeugt man ein BigInteger aus einem String.
String s = "1";
for (int i=1 ; i<=100 ; i++ ) s = s + "0";
BigInteger i = new BigInteger( s );
• Konstanten: ZERO, ONE, TEN
• Instanzmethoden für Grundrechenarten: add, divide, multiply, remainder,
subtract. Beispielsignatur:
BigInteger add(BigInteger val)
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
255
11. Java-Klassenbibliothek
Formatierte Ausgabe
Formatierte Ausgabe
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
256
12. Threads in Java
Einführendes Beispiel
12. Threads in Java
Ein Thread ist eine Folge von Anweisungen, die unabhängig von anderen Threads
parallel zu diesen ausgeführt wird.
• Jeder Thread hat seinen eigenen Stack um lokale Variablen anzulegen und Methoden aufzurufen.
• Alle Threads eines Prozesses teilen sich den Adressbereich des Prozesses (keine
Interprozesskommunikation notwendig).
• Man nennt Threads auch leichtgewichtige Prozesse.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
257
12. Threads in Java
Einführendes Beispiel
Sequentielle Abarbeitung (1)
Wir erzeugen zwei gleichartige Objekte der Klasse ABCPrinter, deren Methode
start() die Großbuchstaben auf der Konsole ausgibt:
public class MehrmalsP {
public static void main(String[] args) {
ABCPrinter p1 = new ABCPrinter();
ABCPrinter p2 = new ABCPrinter();
p1.start();
p2.start();
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
258
12. Threads in Java
Einführendes Beispiel
Sequentielle Abarbeitung (2)
public class ABCPrinter {
public void run() {
for (char c=’A’ ; c<= ’Z’ ; c++) {
System.out.print(c);
Machmal.eineSekundeNix();
}
}
public void start() {
run();
}
}
Liefert die Ausgabe: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ
☞ Sequentielle Abarbeitung
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
259
12. Threads in Java
Einführendes Beispiel
Beispiel: Thread (1)
Aus ABCPrinter machen wir ABCThread, indem wir von der Klasse java.lang.Thread
ableiten.
Die Klasse Thread hat auch schon eine Methode start(), die genau das macht,
was wir benötigen, nämlich die Methode run() aufrufen.
public class ABCThread extends Thread {
public void run() {
for (char c=’A’ ; c<= ’Z’ ; c++) {
System.out.print(c);
Machmal.eineSekundeNix();
}
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
260
12. Threads in Java
Einführendes Beispiel
Beispiel: Thread (2)
In unserem main-Methode benutzen wir nun ABCThread statt ABCPrinter.
public class MehrmalsT {
public static void main(String[] args) {
ABCThread p1 = new ABCThread();
ABCThread p2 = new ABCThread();
p1.start();
p2.start();
}
}
Dies liefert die Ausgabe: AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ
☞ parallele Abarbeitung
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
261
12. Threads in Java
Threads in Java
Threads in Java (1)
• Die parallel auszuführenden Anweisungen müssen in einer Methode run() enthalten sein
• oder von run() aus aufgerufen werden.
• Die Methode start() sorgt dafür, dass run() nebenläufig ausgeführt wird.
• Ruft man run() dagegen direkt auf, entsteht keine Nebenläufigkeit.
• Die Klasse Thread verfügt bereits über eine Methode start().
• und eine Methode run() (die allerdings nichts tut).
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
262
12. Threads in Java
Threads in Java
Threads in Java (2)
• Entscheidend für die Implementierung eines Threads ist nicht die Klasse Thread
sondern die Schnittstelle java.lang.Runnable.
• Runnable definiert eine (abstrakte) Methode run().
• Nur Klassen, die Runnable implementieren, können einen Thread realisieren.
Konsequenz: Zwei Möglichkeiten zur Implementierung von Threads:
• Thread implementiert Runnable, also leiten wir von Thread ab und überschreiben die Methode run().
• Wir implementieren Runnable in einer eigenen Klasse und lassen Objekte dieser
Klasse von Objekten der Klasse Thread kontrollieren.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
263
12. Threads in Java
Threads in Java
Beispiel: Runnable (1)
Hier die zweite Möglichkeit: Wir nutzen implements statt extends.
public class ABCRunnable implements Runnable {
public void run() {
for (char c=’A’ ; c<= ’Z’ ; c++) {
System.out.print(c);
Machmal.eineSekundeNix();
}
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
264
12. Threads in Java
Threads in Java
Beispiel: Runnable (2)
In unserem main-Methode erzeugen wir nun ABCRunnable und steuern diese Objekte mit Hilfe von Objekten der Klasse Thread.
public class MehrmalsR {
public static void main(String[] args) {
Thread t1 = new Thread(new ABCRunnable());
Thread t2 = new Thread(new ABCRunnable());
t1.start();
t2.start();
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
265
12. Threads in Java
Threads in Java
Die Klasse Thread
Konstruktor (u.a.):
• public Thread(Runnable target)
Bei Aufruf von start() wird die run-Methode von target nebenläufig ausgeführt.
Instanzmethoden (u.a.):
• public void start()
• public void run()
• public final boolean isAlive()
liefert true, wenn der Thread gestartet aber noch nicht beendet ist.
• public void interrupt()
setzt das Abbruch-Flag des Threads.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
266
12. Threads in Java
Threads in Java
• public boolean isInterrupted()
liefert true, wenn das Abbruch-Flag gesetzt ist.
Klassenmethoden(u.a.):
• public static Thread currentThread()
liefert eine Referenz auf den Thread, der gerade ausgeführt wird.
• public static void yield()
lässt den Thread, der gerade ausgeführt wird, kurz pausieren, um andere Threads
zum Zuge kommen zu lassen.
• public static void sleep(long millis)
der Thread, der gerade ausgeführt wird, pausiert für millis Millisekunden.
InterruptedException möglich, dabei wird das Abbruch-Flag zurückgesetzt.
• public static boolean interrupted()
liefert true, wenn beim Thread, der gerade ausgeführt wird, das Abbruch-Flag
gesetzt ist.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
267
12. Threads in Java
Threads in Java
Beispiel: sleep
public class Machmal {
public static void eineSekundeNix() {
try {
Thread.sleep(1000);
}
catch(InterruptedException e) { }
}
}
Die Methode sleep() kann eine InterruptedException auslösen.
Das Abbruch-Flag des Threads wird dabei zurückgesetzt.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
268
12. Threads in Java
Threads in Java
Threads vorzeitig beenden
• Threads müssen nicht ihre run-Methode komplett abarbeiten. Vielleicht ist in der
run-Methode auch mit Absicht eine Endlosschleife programmiert.
• Idealerweise nutzen wir die Instanzmethoden interrupt() und isInterrupted().
• Man beachte: Wenn sleep unterbrochen wird, wird eine Exception ausgelöst und
das Abbruch-Flag zurückgesetzt.
• Wenn das Abbruch-Flag gesetzt sein soll, muss deshalb im Exception-Handler
interrupt() aufgerufen werden.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
269
12. Threads in Java
Threads in Java
Lebenszyklus eines Threads
• Nach new ist der Thread erzeugt.
• Mit start() wird der Thread ausführbar.
• Mit run() kann der Thread laufend werden. Dieser Zustand ist ein Spezialfall von
ausführbar.
• Der Thread läuft i.d.R. nicht permanent, sondern wird zwischendurch suspendiert,
z.B. durch yield(). Dann ist er nur noch ausführbar, aber nicht laufend.
• Mit der Terminierung von run() ist der Thread beendet.
• Im Zustand ausführbar kann durch sleep() oder wait() der Thread in den Zustand nicht ausführbar überführt werden.
• Mit Hilfe von notify() wird ein nicht ausführbarer Thread wieder ausführbar.
• Mit Hilfe von isAlive kann ermittelt werden, ob ein Thread in den Zuständen
ausführbar oder nicht ausführbar ist.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
270
12. Threads in Java
Threads in Java
Scheduling
• Ein Scheduler verteilt die zur Verfügung stehende Prozessorzeit auf die einzelnen
Threads.
• Das Scheduling ist nicht spezifiziert, sondern hängt von der virtuellen Maschine
ab.
• Es ist aber sichergestellt, dass ein Thread von höherer Priorität durchschnittlich
mehr Prozessorzeit erhält.
• präemptives Scheduling: Die Threads werden unterbrochen.
• Ein Thread erhält zunächst die Priorität des Threads, der ihn erzeugt. Der mainThread hat die Priorität 5 (NORM PRIORITY).
• Methoden zur Steuerung der Priorität: getPriority und setPriority.
• Höchste Priorität gleich 10 (MAX PRIORITY), niedrigste gleich 1 (MIN PRIORITY).
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
271
12. Threads in Java
Synchronisation
Synchronisation
• Ein Thread schreibt Werte in ein Objekt, ein anderes liest Werte aus dem selben
Objekt.
• Wird der schreibende Thread unterbrochen, bevor er den Schreibvorgang komplett
abgeschlossen hat, liest der andere Thread inkonsistente Werte.
• Leser/Schreiber-Problem
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
272
12. Threads in Java
Synchronisation
Beispiel: Leser/Schreiber (1)
public class Sequenz {
private static int zaehler = 0;
public static void nachster() {
int zahl = zaehler;
eine Anweisung die lange dauert ...
System.out.print(" " + zahl);
zaehler++;
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
273
12. Threads in Java
Synchronisation
Beispiel: Leser/Schreiber (2)
public class ZaehlThread extends Thread {
public void run() {
for (;;)
Sequenz.naechster();
}
}
Wie sieht die Ausgabe u.U. aus, wenn zwei ZaehlThreads parallel laufen?
0 1 2 2 4 5 6 6 8 ...
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
274
12. Threads in Java
Synchronisation
Sperren, Monitor
• Das Problem des letzten Beispiels können wir prinzipiell durch Sperren (Locks)
lösen.
• Immer wenn ein Thread die Methode naechster() betritt, wird diese Methode
für alle anderen Threads gesperrt.
• Threads, die eine gesperrte Methode betreten wollen, werden solange supendiert,
bis die Sperre freigegeben wird.
• Die Sperre wird freigegeben, sobald der ausführende Thread die Methode
naechster() verlassen hat.
• Nun kann ein anderer Thread in die Methode naechster() eintreten. Damit
sperrt er diese Methode wiederum für alle anderen Threads.
• Fazit: maximal ein Thread soll sich in der Methode naechster() befinden (kritischer Abschnitt).
• In der Programmierung bezeichnet man dies als Monitor.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
275
12. Threads in Java
Synchronisation
Monitor mit synchronized
• In Java ist es leicht, einen Monitor zu implementieren.
• Mit dem Schlüsselwort synchronized erreichen wir, dass sich maximal ein
Thread in der durch synchronized gekennzeichneten Methode befinden darf.
synchronized public static void naechster() { ... }
Damit wäre gewährleistet, dass unsere ZaehlThreads eine korrekte Sequenz ausgeben:
0 1 2 3 4 5 6 7 8 ...
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
276
12. Threads in Java
Synchronisation
Klassen- und Instanzmethoden mit synchronized
• Eine mit synchronized gekennzeichnete Klassenmethode kann höchstens von
einem Thread gleichzeitig ausgeführt werden.
• Eine mit synchronized gekennzeichnete Instanzmethode kann prinzipiell von
mehreren Threads gleichzeitig ausgeführt werden.
• Aber für jedes Objekt kann es maximal einen Thread geben, der sich in einer mit
synchronized gekennzeichneten Instanzmethode befindet.
• Bei Instanzmethoden ist die Synchronisation also objektbezogen.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
277
12. Threads in Java
Synchronisation
Das Erzeuger/Verbraucher-Problem
Wir betrachten einen (zunächst abstrakten) einfachen Puffer, der maximal einen
Integer-Wert aufnehmen kann.
abstract class Wert {
protected int wert;
abstract public int get();
abstract public void put(int w);
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
278
12. Threads in Java
Synchronisation
Solch ein Puffer wird von einem Erzeuger-Thread mit den Werten von 0 bis 4 gefüllt.
class Erzeuger extends Thread {
Wert w;
public Erzeuger(Wert w) { this.w = w; }
public void run() {
for (int i=0 ; i<5 ; i++) {
w.put(i);
System.out.println("Erzeuger
put: " + i);
try {
sleep((int) (Math.random() * 100));
}
catch(InterruptedException e) { }
}
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
279
12. Threads in Java
Synchronisation
Ein Verbraucher-Thread holt die Werte aus dem Puffer.
class Verbraucher extends Thread {
Wert w;
public Verbraucher(Wert w) { this.w = w; }
public void run() {
int v;
for (int i=0 ; i<5 ; i++) {
v = w.get();
System.out.println("Verbraucher get: " + v);
try {
sleep((int) (Math.random() * 100));
}
catch(InterruptedException e) { }
}
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
280
12. Threads in Java
Synchronisation
Wir spezialisieren die Pufferklasse Wert zunächst auf einfache Weise:
class SchlechterWert extends Wert {
public synchronized int get() { return wert; }
public synchronized void put(int w) { wert = w; }
}
Unser Testprogramm
public class EVTest1 {
public static void main(String[] args) {
Wert
w = new SchlechterWert();
Erzeuger
e = new Erzeuger(w);
Verbraucher w = new Verbraucher(w);
e.start();
v.start();
}
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
281
12. Threads in Java
Möglicher Ablauf:
Erzeuger
put:
Verbraucher get:
Erzeuger
put:
Verbraucher get:
Verbraucher get:
Verbraucher get:
Erzeuger
put:
Erzeuger
put:
Erzeuger
put:
Verbraucher get:
Synchronisation
0
0
1
1
1
1
2
3
4
4
• Der Erzeuger produziert zwar die Werte 0 bis
4,
• der Verbraucher entnimmt dem Puffer aber einige Werte mehrfach bzw. einige überhaupt
nicht.
• Wir müssen dafür sorgen, dass der Verbraucher immer nur dann aktiv wird, wenn der
Erzeuger wieder einen neuen Wert bereitgestellt hat.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
282
12. Threads in Java
Synchronisation
Object-Methoden zur Steuerung von Threads
Die Klasse Object stellt zur Verfügung:
• public final void wait()
der Thread, der gerade ausgeführt wird, wird suspendiert, bis ein anderer Thread
notify oder notifyAll für das aktuelle Objekt ausführt.
• public final void notify()
reaktiviert einen einzelnen Thread, der sich im Wartezustand bezüglich des aktuellen Objekts befindet.
• public final void notifyAll()
reaktiviert alle Thread, die sich im Wartezustand bezüglich des aktuellen Objekts
befinden.
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
283
12. Threads in Java
Synchronisation
Eine bessere Spezialisierung des abstrakten Puffers:
class GuterWert extends Wert {
private boolean verfuegbar = false;
public synchronized int get() {
if (!verfuegbar)
try {
wait();
}
catch (InterruptedException ie) { }
verfuegbar = false;
notify();
return wert;
}
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
284
12. Threads in Java
Synchronisation
public synchronized int put(int w) {
if (verfuegbar)
try {
wait();
}
catch (InterruptedException ie) { }
wert = w;
verfuegbar = true;
notify();
}
}
• Das Flag verfuegbar zeigt an, ob ein Wert bereitsteht.
• Kein Wert verfügbar, dann wait() in get().
• put() weckt mit notify() den Verbraucher-Thread, wenn Wert zur Verfügung
steht.
• put()/get() analog
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
285
12. Threads in Java
Synchronisation
Im Testprogramm ändern wir die Zeile zur Erzeugung des Puffers:
Wert w = new GuterWert();
Damit erhalten wir dann eine saubere Verarbeitung:
Erzeuger
Verbraucher
Erzeuger
Verbraucher
Erzeuger
Verbraucher
Erzeuger
Verbraucher
Erzeuger
Verbraucher
put:
get:
put:
get:
put:
get:
put:
get:
put:
get:
0
0
1
1
2
2
3
3
4
4
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
286
12. Threads in Java
Synchronisation
Zusammenfassung
•
•
•
•
Threads: parallele Kontrollflüsse in einem Programm
Implementierung: implements Runnable oder extends Thread
kritische Bereiche, Monitor: synchronized
Gegenseitiges Warten: wait(), notify()
Peter Becker, Programiersprache Java — FH Bonn-Rhein-Sieg, SS 08
287
Herunterladen