Grundzüge der Informatik V10. Objektorientiere Konzepte in Java Prof. Dr. Max Mühlhäuser FG Telekooperation TU-Darmstadt Agenda • Die Wurzelklasse "Object" • Wrapper-Klassen: eine Brücke zwischen Primitiven und Referenztypen • Objekterzeugung: Initialisierung mit Konstruktoren • Überladen von Methoden • Schnittstellen 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 2 Die Klasse Object • java.lang.Object ist die Superklasse aller Java-Klassen – Object selbst besitzt – als einzige Java-Klasse – keine Superklasse – Object ist die Wurzelklasse der Java-Klassenhierarchie • Jede Java-Klasse, bei deren Deklaration der extends-Teil nicht angegeben wird, ist automatisch eine direkte Unterklasse von Object • Daraus folgt – jede Java-Klasse erbt – direkt oder indirekt – alle Methoden von Object – In einer Variable des Typs Object können beliebige Objekte gespeichert werden – praktisch um Listen und andere Datenstrukturen allgemein zu programmieren (siehe später V15: Datenstrukturen) 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 3 Vordefinierte Methoden in Object • In Object vordefinierte Methoden sind in allen anderen Objekten auch definiert Æ Verwendung bei jedem Typ möglich • Die wichtigsten vordefinierten Methoden sind bereits bekannt – boolean equals(Object o) – Objektvergleich – String toString() – Gibt die String-Repräsentation des Objekts zurück • Weitere vordefinierte Methoden für fortgeschrittene Programmierkonzepte (Threadsynchronisation, Hashtables, etc.) • Grundfunktionalität der vordefinierten Methoden vorhanden, aber sehr allgemein Æ Überschreiben meist sehr sinnvoll 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 4 Wrapper-Klassen • Primitive Datentypen (int, boolean, etc.) sind keine Klassen Æ sind nicht von Object abgeleitet, haben keine Methoden Æ können nicht an Variablen des Typs Object zugewiesen werden • Zuweisung zu Object manchmal wünschenswert Æ Wrapper-Klassen (Hüllklassen) 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 5 Wrapper-Klassen Verwendung von Wrapper-Klassen • Name: meist wie primitiver Datentyp, aber Anfangsbuchstabe großgeschrieben; Package java.lang – java.lang.Byte, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Float, java.lang.Double, java.lang.Character • Objekte sind immutable – Wert-Zuweisung über Konstruktor – Wertabfrage über <primitive-Type>Value() 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 6 Wrapper-Klassen Object Object • Unschön: int und Integer sind bei Zuweisung nicht konform. Das gleiche gilt für die anderen Typen auch. Number int i = 5; Number Integer iobj = new Integer(); iobj = i; // Error ! Integer int Integer int i = iobj; // Error ! // Konversion per Konstruktor Konstruktor iobj = new Integer(i); // oder Konvertierungsmethode intValue() i = iobj.intValue(); 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 7 Casting • Erinnern Sie sich? (V.3) – b akzeptiert alle Roboter der Klassen B und C und deren Erben (Transitivität der Relation) A – b akzeptiert Methoden die A und B anbieten B – b akzeptiert keine Methoden, die in C, aber nicht in A oder B sind • Was ist mit damit: B b = new C(); b.methodDefinedInC(); C – Funktioniert nicht, weil b keine Methoden aus C akzeptiert • Aber: wir wissen, dass in b ein Objekts von Typ C gespeichert ist 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 8 Casting • Zuweisung an Subtypen möglich über Casting • Syntax: <Cast> ::= (<Type>)<Object-Expression> • Bedeutung: „Nimm das Objekt und behandle es, als sei es vom Typ <Type>“ • Falls das Objekt nicht in den angegebenen Typ umgewandelt werden kann, tritt ein Laufzeitfehler auf (ClassCastException) • Beispiel B b = new C(); C c =(C)b; // Funktioniert c.methodDefinedInC(); // Funktioniert b = new B(); c = (C)b; 12. 12. 2002 © MM ... // erzeugt Laufzeitfehler, da b nicht vom Typ C GDI - OO-Konzepte in Java 9 Der instanceof Operator • Wie kann man testen ob ein Cast funktioniert? • Lösung: Abfrage des dynamischen Typs einer Variable mit instanceof • Syntax: <Instance-Of> ::= <Object-Expression> instanceof <Type> • instanceof ergibt true, wenn <Object-Expression> an eine Variable des Typs <Type> zugewiesen werden kann – Ausnahme: Ist <Object-Expression> == null, so liefert instanceof immer false 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 10 Der instanceof Operator Beispiel public class InstanceOfExample { // Die Klassen A, B, C existieren wie auf S. 8 angegeben public static void printCompatibility(A obj) { if(obj instanceof C) { System.out.println("obj ist vom Typ C"); } if(obj instanceof B) { System.out.println("obj ist vom Typ B"); } if(obj instanceof A) { System.out.println("obj ist vom Typ A"); } // ... 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 11 Der instanceof Operator // ... public static void main(String[] args) { printCompatibility(new A()); // Ergebnis: // obj ist vom Typ A printCompatibility(new B()); // Ergebnis: // obj ist vom Typ B // obj ist vom Typ A printCompatibility(new C()); // Ergebnis: // obj ist vom Typ C // obj ist vom Typ B // obj ist vom Typ A } } 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 12 Objektinitialisierung mit Konstruktoren • Bei der Definition einer Klasse können Konstruktoren deklariert werden. • Konstruktoren werden für Initialisierungen der Attribute mit Werten benutzt, wenn der konkrete Wert erst zum Zeitpunkt der Objekterzeugung und nicht bereits bei der Übersetzung der Klassendefinition bekannt ist 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 13 Objektinitialisierung mit Konstruktoren • Eine Klassendefinition kann beliebig viele Konstruktoren enthalten (stellt verschiedene Initialisierungs-Vorschriften zur Verfügung) Æ explizite Konstruktoren • Falls kein Konstruktor explizit deklariert wird, wird ein parameterloser Konstruktor automatisch generiert • Alle Konstruktoren haben den gleichen Namen Æ Klassenname – unterscheiden sich nur in der Anzahl und Typ der Parameter – Überladung der Konstruktoren • Im Gegensatz zu Methoden haben Konstruktoren keinen Rückgabetyp 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 14 Objektinitialisierung mit Konstruktoren • Syntax <Constructor> ::= <Modifier> <Class-Name> (<Parameter-List>) <Throws-Clause> { <Statements> } <Parameter-List> ::= <Parameter> | <Parameter> , <Parameter-List> <Parameter> ::= <Type> <Identifier> < Throws-Clause> : kommt später, vorerst ε 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 15 Objektinitialisierung mit Konstruktoren Beispiel: Kreis • Ein Kreis ist durch die Koordinaten des Ursprungs (x, y) und einen Radius definiert : ohne Konstruktor sind die Anfangswerte 0 class Circle { double x, y, radius; Circle(double xx, double yy, double rr){ x = xx; y = yy; Initialisierung der radius = rr; Attributwerte beim Erzeugen } eines Kreis-Objektes double perimeter() { ... } double area() { ... } } 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 16 Objektinitialisierung mit Konstruktoren Beispiel: Kreis class Display { // Kreise werden immer relativ zu // ( 0.0, 0.0 ) erzeugt Circle k = new Circle(2.5); Was passiert beim Übersetzen dieser Klasse? // also geben wir beim Erzeugen // nur den Radius an Circle k2 = new Circle(); // oder nichts k2.r = 1.0; // und setzen Radius später ... Mit der jetzigen Implementierung ist Circle() nicht erlaubt Æ Fehler } 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 17 Objektinitialisierung mit Konstruktoren Beispiel: Kreis • Werden verschiedene Initialisierungsvorschriften für Kreise benötigt, dann müssen verschiedene überladene Konstruktoren in der Klasse Kreis implementiert werden – Circle(double xx, double yy, double rr) – Circle(double rr) – Circle() 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 18 Überladen der Konstruktoren Beispiel: Kreis class Circle { double x, y, r; Circle(double xx, double yy, double rr) { x = xx; y = yy; r = rr; } Circle(double rr) { r = rr; } Circle() { } Nur dann automatisch eingefügt, wenn kein Konstruktor explizit definiert wird double perimeter() {return ...; } double area() { return ...; } } 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 19 Aufruf eines anderen Konstruktors der selben Klasse class Circle { double x, y, r; Circle(double xx, Alternative: den eigenen Konstruktor mithilfe von this() aufrufen double yy, double rr) { x = xx; y = yy; r = rr; } Circle(double rr) { this(0.0, 0.0, rr); } Circle() { this(0.0, 0.0, 1.0); } double perimeter() { ... ; } double area() { ... ; } } 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 20 Aufruf eines anderen Konstruktors • Der Aufruf eines anderen Konstruktors muss die erste Anweisung des Konstruktors sein – Daher ist innerhalb eines Konstruktors nur maximal ein weiterer Konstruktoraufruf möglich – Ein anderer Konstruktor der eigenen Klasse kann über this(<Parameter-List>) aufgerufen werden – Ein Konstruktor einer Superklasse kann über super(<ParameterList>) aufgerufen werden • Welche der Konstruktorvarianten innerhalb eines expliziten Aufrufs tatsächlich verwendet wird, wird über die Parameteranzahl bzw. die Parametertypen spezifiziert • Der aufgerufene Konstruktor darf selbst wieder einen weiteren Konstruktor aufrufen 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 21 Konstruktoren und Automatismen • Wird in einem Konstruktor kein anderer Konstruktor explizit aufgerufen, ist dies äquivalent zu super(); am Beginn des Konstruktors • Wird kein Konstruktor deklariert, so erzeugt Java automatisch – Einen parameterlosen Konstruktor, der super() aufruft Æ Enthält die Basisklasse keinen parameterlosen Konstruktor, so schlagen die Automatismen fehl – In diesem Fall muss ein anderer Konstruktor von Hand aufgerufen werden 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 22 Überladen von Methoden • Konstruktoren werden in Java überladen – alle Konstruktoren einer Klasse haben den gleichen Namen im gleichen Namensraum... – ... aber unterschiedliche Signaturen Æ unterschiedliche formale Argumenttypen und -anzahl • Nicht nur Konstruktoren können überladen werden, sondern auch beliebige (geerbte oder eigene) Methoden 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 23 Beispiel Überladen von Methoden class SimplePrinter { void print( int i ) { .. }; } class Printer extends SimplePrinter void print(int i) { .. }; int print(int i) { .. }; void print(boolean i) { .. }; } { FEHLER! Überschreibung nur mit identischer Signatur möglich 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 24 Überladen von Methoden • Überschreibung bei Vererbung: Eine Methode kann in einer Unterklasse mit dem gleichen Namen und Signatur wie eine Methode in der Superklasse definiert werden • Eine Methode kann gleichzeitig überladen und überschrieben werden: – in der Unterklasse kann die überschriebene Methode als super.methodenName() bzw. der überladene Konstruktor der Superklasse als super() aufgerufen werden • Beim Überladen wird der Rückgabetyp nicht zur Unterscheidung von Methoden herangezogen 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 25 "Ad hoc" Polymorphie Signatur: void methode(Object) Die Methodennamen sind überladen. Die Unterscheidung basiert auf Parametertypen bzw. Anzahl Der Compiler erkennt die Typen und wählt die Methode statisch aus (compile time binding) 12. 12. 2002 © MM ... void methode(Object o) { ... } void methode(Person p) { ... } static void main( .. ) { Object p=Person(); methode(p); GDI - OO-Konzepte in Java 26 Polymorphismus und OOP • Monomorphe Sprachen (Typsysteme): es wird strikt ein Typ für jede Programmeinheit definiert (z.B. Pascal) • Polymorphie („Vielgestaltigkeit“): Eine Programmeinheit kann verschiedene Typen haben und somit verschiedene Eigenschaften während der Laufzeit Polymorphie ad-hoc universal overloading coercion parametric inclusion Überladung Typkonversion Generizität Vererbung 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 27 Polymorphie und OOP • Überladung: Verschiedene Methoden haben den gleichen Namen (z.B. equals für verschiedene Typen) • Typkonversion/Casting: Umwandlung des Typs eines Wertes (z.B. (int)2.5) • Generizität: Typvariablen müssen zunächst einen Typ erhalten bevor ein Typ oder eine Methode benutzt werden kann (z.B. Arraytyp) • Vererbung: Variablen haben neben einem statischen Typ auch einen dynamischen, der vom Typ des referenzierten Objekts abhängt – Der dynamische Typ bestimmt welche Implementierung (innerhalb einer Vererbungshierachie) einer Methode bei einem Aufruf zur Anwendung kommt 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 28 Schnittstellen • Schnittstellen (Interfaces) definieren Dienstleistungen für andere Klassen, ohne etwas über die Implementierung der Dienstleistungen festzulegen – bestehen nur aus Methodensignaturen sowie Konstantendefinitionen • stellen funktionale Abstraktionen bereit, die das „Was“, aber nicht das „Wie“ festlegen UML Notation <<interface>> public interface anInterface { AnInterface method() 12. 12. 2002 © MM ... public void method(); } GDI - OO-Konzepte in Java 29 Schnittstellen • Analog wie Variablen vom Klassentyp, können auch Variablen vom Schnittstellentyp deklariert werden: <Reference-Type> ::= <Class-Name> | <Interface-Name> | <Array-Type> // in der Klasse anInterfaceClient AnInterface anObject; anObject.method(); // OK 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 30 Schnittstellen • Die Implementierung der abstrakten Methoden erfolgt durch Java-Klassen • Wenn eine Klasse eine Schnittstelle implementiert, dann muss sie alle Methoden der Schnittstelle implementieren. Auch leere Implementierungen sind erlaubt, z.B. durch „{}“ implements AnInterface { <<interface>> AnInterface method() public void method() { } Empty Implementation } UML Notation für implements class EmptyImplementation method() 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 31 Schnittstellen • Verschiedene Java-Klassen können dieselbe Schnittstelle auf unterschiedliche Weise implementieren • Die Definition der Klienten-Klasse der Schnittstelle kann ohne Änderung in Objekten aller Implementierungsklassen wiederverwendet werden, da sie nur die Schnittstelle anspricht und diese unverändert bleibt 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 32 Schnittstellen Aufrufende Klasse Aufruf <<interface>> Schnittstelle Schnittstelle wird implementiert von Klasse 1 Klasse1 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java Schnittstelle wird implementiert von Klasse 2 Klasse2 33 Schnittstellen Verwendungsbeispiel • Alle geometrischen Figuren verstehen die Nachricht paint(), in der sie ihre spezifische Form zeichnen. • Die Tatsache, dass alle geometrischen Figuren sich zeichnen können, spiegelt sich in der Präsenz der nicht implementierten (abstrakten) Methode paint() in der Schnittstelle ShapeDisplay wieder • Alle konkreten Klassen für geometrische Figuren (Circle, Line, ...) implementieren die Schnittstelle ShapeDisplay – Jede dieser Klassen implementiert die Methode paint() in einer spezifischen Weise: Ein Rechteck verwendet ein anderes Verfahren, um sich zu zeichnen, als ein Kreis 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 34 Schnittstellen Verwendungsbeispiel <<interface>> ShapeDisplay void paint() Schnittstelle wird von Line implementiert Schnittstelle wird von Circle implementiert 12. 12. 2002 © MM ... Circle Line void paint() void paint() GDI - OO-Konzepte in Java 35 Schnittstellen Verwendungsbeispiel • Die Klasse Display verwaltet eine Liste von geometrischen Figuren, welche unterschiedlichen Typs sein können (Kreise, Linien, ...) • Wenn der Benutzer einen bestimmten Button drückt, werden alle Elemente der Liste aufgefordert, sich zu zeichnen, indem die Methode paint() an jedes Element vorgenommen wird • Für Display ist der konkrete Typ der einzelnen Elemente der Liste irrelevant. Alles was Display interessiert ist, dass alle Elemente der Liste die Schnittstelle ShapeDisplay implementieren Æ die Methode paint() (auf ihre Weise) ausführen können 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 36 Verwendungsbeispiel Display paintAll() 12. 12. 2002 © MM ... Schnittstellen paint() <<interface>> ShapeDisplay void paint() Circle Line void paint() void paint() GDI - OO-Konzepte in Java 37 Schnittstellen class Display { ee t t ejekk j OObb llele l aa e nne h cich i ZZee ShapeDisplay[] shapes; ... public void paintAll() { ... } } Starte Starte mit mit dem dem ersten ersten Feldelement Feldelement und und solange solange das das letzte letzte Element Element noch noch nicht nicht erreicht erreicht ist, ist, verfahre verfahre wie wie folgt: folgt: •• sende sende der der Figur, Figur, auf auf welche welche der der aktuelle aktuelle Verweis Verweis liste[i] liste[i] zeigt, zeigt, die die Nachricht Nachricht paint() paint() •• fahre fahre mit mit dem dem nächsten nächsten Element Element fort fort 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 38 Schnittstellen Verwendungsbeispiel class Display { private ShapeDisplay[] shapes; public Display(ShapeDisplay[] gsList) { shapes = gsList; } public void paintAll() { for(int i = 0; i < shapes.length; i++) { if(shapes[i] != null) { shapes[i].paint(); } } } } 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 39 Schnittstellen Verwendungsbeispiel ttee k eek j j OObb llele l aa e nne h cich i ZZee • Das übergeordnete Zeichenverfahren paintAll() kann spezifiziert werden, ohne die aktuellen Typen der Figuren zu kennen • Man kann neue Typen von geometrischen Figuren später implementieren • Man kann Exemplare von später erzeugten Typen in der Liste hinzufügen, ohne das Zeichenverfahren von paintAll() anpassen zu müssen • Der Dienstabnehmer (Display) ist unabhängig vom Dienstanbieter (die konkreten ShapeDisplay Klassen). 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 40 Java: Syntax und Semantik • Eine Klasse kann nur eine direkte Superklasse besitzen (Einfachvererbung) • Aber: Eine Klasse kann mehrere Schnittstellen implementieren (eine Art Mehrfachvererbung) • Methoden, die eine Schnittstellen-Methode implementieren, müssen public sein • Typ-Signatur der implementierenden Methode Ù Typ-Signatur, die in der Schnittstellen-Definition spezifiziert ist • Klassen, die Schnittstellen implementieren, können eigene zusätzliche Methoden definieren 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 41 Konstanten in Schnittstellen • Durch die Deklaration von Konstanten in Schnittstellen kann sichergestellt werden, dass spezielle konstante Werte überall konsistent zur Anwendung kommen • Es handelt sich um öffentliche (public) konstante Klassenattribute 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 42 Konstante in Schnittstellen interface Bildschirmformate { final int X_VGA = 600, Y_VGA = 480; final int X_SVGA = 800, Y_SVGA = 600; ... } class Fenster { if(bildschirmformat == Bildschirmformate.VGA) setSize(Bildschirmformate.X_VGA, Bildschirmformate.Y_VGA); else ... } 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java 43 Schnittstellen und Vererbung • Jede Schnittstelle kann von einer oder mehreren Oberschnittstellen erben (Schlüsselwort extends) • Wenn eine Klasse eine Schnittstelle2 implementiert, die Erbe einer Schnittstelle1 ist, muss die Klasse alle Methoden implementieren, die in der Schnittstellenvererbungskette definiert sind 12. 12. 2002 © MM ... GDI - OO-Konzepte in Java <<interface>> Schnittstelle1 method1(); method2(); <<interface>> Schnittstelle2 method3(); MyClass 44