Vererbung und Polymorphismus - DBIS Informatik

Werbung
Vererbung und
Polymorphismus
Programmiermethodik
Eva Zangerle
Universität Innsbruck
Überblick
Vererbung allgemein
Einführung
Java – Ein erster Überblick
Objektorientierung
Vererbung der Spezifikation in Java
Vererbung der Implementierung in Java
Vererbung und Polymorphismus
Ausnahmebehandlung
Pakete und Javadoc
Spezielle Themen
Abstrakte Klassen
Die Klasse Object
Generische Programmierung
Java Collection-Framework
Libraries
Streams
Unit-Tests
GUI-Programmierung
Entwurfsmuster
Java Virtual Machine
Ausblick
Programmiermethodik - Objektorientierung
2
Vererbung allgemein
Vererbung allgemein
• Klassen modellieren Dinge der realen Welt.
• Klassen sind oft Gruppierungen von gleichartigen Objekten.
• Diese Dinge kommen oft in verschiedenen Varianten vor, die
man durch Klassifikation hierarchisch gliedern kann.
• Programme sollten


mit den verschiedenen Varianten arbeiten und
in bestimmten Situationen Varianten nicht unbedingt unterscheiden
(gleich behandeln).
• Java bietet die Möglichkeit


hierarchische Klassenstrukturen zu bilden und
Varianten von Objekten gleich zu behandeln.
Programmiermethodik - Vererbung und Polymorphismus
4
Beispiel für Vererbungshierarchie
Typebene
Person
Student
Employee
Professor
Personen die
weder Studenten
noch Bedienstete
sind
Assistant
InstanzEbene
Person
Employee
Student
Programmiermethodik - Vererbung und Polymorphismus
Professor
Assistant
5
Unterklassen und Oberklassen
• Eine Klasse S ist eine Unterklasse der Klasse A, wenn S die
Spezifikation von A erfüllt, umgekehrt aber A nicht die
Spezifikation von S (A ist eine Oberklasse von S).


Beziehung zwischen A und S wird Spezialisierung genannt.
Beziehung zwischen S und A wird Generalisierung genannt.
Programmiermethodik - Vererbung und Polymorphismus
[Lahres 2006]
6
Prinzip der Ersetzbarkeit
• Wenn eine Klasse B eine Unterklasse der Klasse A ist, dann
können in einem Programm alle Exemplare der Klasse A
durch Exemplare der Klasse B ersetzt werden und es gelten
weiterhin alle zugesicherten Eigenschaften der Klasse A.

Exemplare der Unterklasse sind gleichzeitig Exemplare der Oberklasse
in Bezug auf die der Oberklasse zugrunde liegende Spezifikation.
• Vorbedingungen, Nachbedingungen und Invarianten gelten
auch dann, wenn Exemplare der Oberklasse durch Exemplare
der Unterklasse ersetzt werden.
• Beispiele folgen noch!
Programmiermethodik - Vererbung und Polymorphismus
7
Kategorien von Klassen
•
Klassen können kategorisiert
werden.

•
Abhängig davon, in welchem
Umfang sie selbst für die von
ihnen spezifizierte Schnittstelle
auch Methoden anbieten.
Kategorien:
1.
2.
3.
Konkrete Klassen
Rein spezifizierende Klassen
(Schnittstellen-Klassen)
Abstrakte Klassen
[Lahres 2006]
Programmiermethodik - Vererbung und Polymorphismus
8
Konkrete Klassen
• Stellen für alle von der Klasse spezifizierte Operationen auch
Methoden bereit.
• Es können Instanzen erzeugt werden.
• Wurden bisher in dieser Vorlesung besprochen.
• Stellt im Grunde auch Schnittstellen zur Verfügung, diese
sind jedoch auch implementiert.
public class ArrayStack {
private final String[] data;
private int position = 0;
public void push(String s) {
if (this.position < this.data.length) {
this.data[this.position] = s;
this.position++;
} else {
System.err.println("could not insert");
}
}
Programmiermethodik - Vererbung und Polymorphismus
9
Schnittstellen-Klassen
• Schnittstellen-Klassen (Interfaces)




Dienen alleine der Spezifikation einer Menge von Operationen ("was").
Für keine Operation wird eine Implementierung bereitgestellt ("wie").
Es können keine Instanzen erzeugt werden.
Trennung Spezifikation vs. Implementierung
• „Eine Schnittstelle implementieren“

Unterklasse implementiert die Schnittstelle, wenn eine Unterklasse einer
Schnittstellen-Klasse Methoden für alle von der Schnittstelle spezifizierten
Operationen bereitstellt.
• Einsatz


Bei statisch typisierten Programmiersprachen (wie Java)
Gemeinsamer Typ für Klassen, die Interfaces implementieren.
public interface Stack {
String pop(); // get top element
int size(); // get no of elements
void push(String s); // push element on top
}
Programmiermethodik - Vererbung und Polymorphismus
10
Abstrakte Klassen
• Abstrakte Klassen

Stellen meist für mindestens eine der spezifizierten Operationen
keine Implementierung bereit.
 Spezialfall: Alle Methoden implementiert, Klasse aber als abstrakt markiert
(siehe Abschnitt über abstrakte Klassen)



Es kann keine direkten Instanzen geben.
Alle Instanzen einer abstrakten Klasse müssen gleichzeitig Instanzen
einer nicht abstrakten Unterklasse sein.
Zwischenstufe zwischen Interfaces und konkreten Klassen.
• Abstrakte Methoden



Erlauben eine Operation für eine Klasse zu definieren, ohne dafür
eine Methodenimplementierung zur Verfügung zu stellen.
Methode dient nur zur Spezifikation.
Eine Implementierung erfolgt in einer abgeleiteten konkreten
Unterklasse.
Programmiermethodik - Vererbung und Polymorphismus
11
Abstrakte Klassen
public abstract class DefaultStack implements Stack {
// provide default implementation for peek
public Object peek() {
Object o = this.pop();
this.push(o);
return o;
}
// leave remaining stack operations open
// for concrete classes
public abstract Object pop();
public abstract boolean isEmpty();
public abstract void push(Object obj);
}
Programmiermethodik - Vererbung und Polymorphismus
12
Polymorphismus
• Polymorph = „vielgestaltig“
• Eine Variable oder eine
Methode kann gleichzeitig
mehrere Typen haben.
• Objektorientierte Sprachen
sind polymorph.
(konventionelle Sprachen wie
zum Beispiel Pascal sind
monomorph)
• Verschiedene Arten (siehe
rechts)
Programmiermethodik - Vererbung und Polymorphismus
Polymorphismus
Universeller Polymorphismus
Ad-hoc Polymorphismus
Parametrischer
Polymorphismus
Überladen
Inklusions-/
Vererbungspolymorphismus
Typumwandlung
13
Polymorphismus (Arten)
• Universeller Polymorphismus


Ein Name oder Wert kann theoretisch unendlich viele Typen besitzen.
Die Implementierung einer universell polymorphen Operation führt
generell gleichen Code unabhängig von den Typen Ihrer Argumente
aus.
• Ad-hoc-Polymorphismus



Ein Name oder ein Wert kann nur endlich viele verschiedene Typen
besitzen.
Typen sind zur Übersetzungszeit bekannt.
Ad-hoc-polymorphe (also überladene) Operationen können abhängig
von den Typen ihrer Argumente unterschiedlich implementiert sein.
Programmiermethodik - Vererbung und Polymorphismus
14
Polymorphismus in dieser Vorlesung
• Ad-hoc-Polymorphismus wurde schon behandelt


Siehe Typumwandlung
Siehe Überladen von Methoden
• Universeller Polymorphismus


Parametrischer Polymorphismus wird noch behandelt (Generische
Programmierung).
Inklusionspolymorphismus ist zentrales Thema dieses Foliensatzes.
• Inklusionspolymorphismus


Ersetzbarkeitsprinzip
Dynamische Polymorphie
Programmiermethodik - Vererbung und Polymorphismus
15
Vererbung der Spezifikation in Java
Interfaces
• Inhalt

Methoden-Spezifikation ohne Rumpf
 Sind abstrakte Methoden
 Sind immer public
 Keine Konstruktoren

Konstanten
 Alle Objektvariablen sind immer public static final (nur Konstanten).
• Implementierung

Eine Klasse kann Interfaces implementieren.
Programmiermethodik - Vererbung und Polymorphismus
17
Exkurs: final
• verschiedene Dinge können als final gekennzeichnet werden
• Klassenvariablen
• Objektvariablen
• lokale Variablen
• Methodenparameter
• Methoden und Klassen (später)
• Bedeutung
• finale Variable oder Parameter kann nur maximal einmal einen Wert
zugewiesen bekommen, danach besteht nur noch Lesezugriff
• bei Klassenvariablen, Objektvariablen und Parametern geschieht dies
genau einmal
• Klassenvariablen: bei Deklaration oder im statischen Initialisierungsblock
• Objektvariablen: bei Deklaration oder im Konstruktor
• Parameter: beim Aufruf der Methode
• Achtung bei Variablen von Referenztypen: Referenz bleibt unverändert, aber Objekt
kann sich ändern
Programmiermethodik - Vererbung und Polymorphismus
18
Klassen und Interfaces
• Klassen implementieren Interfaces (mit implements).
• Man kann keine Objekte von Interfaces anlegen.
• Eine Klasse kann mehrere Interfaces implementieren.
• Ein Interface kann von mehreren Klassen implementiert
werden.
• Die Implementierung eines Interfaces muss die Spezifikation
erfüllen.

Alle Methoden müssen implementiert werden (Ausnahmen werden
noch besprochen; Eclipse-Hilfestellung).
• Die entsprechenden Konstruktoren müssen in den Klassen
implementiert werden (nicht im Interface).
Programmiermethodik - Vererbung und Polymorphismus
19
Beispiel (Komplexe Zahlen)
• Einfaches Interface für komplexe Zahlen
public interface Complex {
double getReal();
double getImag();
double getDistance();
double getPhase();
}
• Alle Methoden sind implizit public und abstract.

Könnte man angeben, muss man aber nicht.
• Jede Klasse, die dieses Interface implementiert, muss die 4
angegebenen Methoden implementieren.
• Beispiel: Siehe externes Beispiel Complex.java,
Polar.java und Cartesian.java
Programmiermethodik - Vererbung und Polymorphismus
20
Externes Beispiel in Worten
• Klasse Cartesian und Polar implementieren das Interface
Complex.
• Beide Klassen implementieren die vorgegebenen Methoden
(jeweils unterschiedlich).
• Beide Klassen geben zusätzlich einen Konstruktor an.



Die Form des Konstruktors wird nicht vom Interface vorgegeben.
Es könnten noch mehrere Konstruktoren angegeben werden.
Es können zusätzliche Methoden angegeben werden (add, sub etc.) –
d.h. es gibt keine Einschränkung für weitere Methoden.
• Beide Klassen sind gleichberechtigte und unabhängige
Implementierungen von Complex.
Programmiermethodik - Vererbung und Polymorphismus
21
Polymorphismus
• Interfaces definieren einen Typ.


Können in Variablendeklarationen, Parameterlisten, und als
Ergebnistyp von Methoden verwendet werden.
c ist vom Typ Complex.
• Warum funktioniert das Beispiel?



Alle Klassen implementieren das Interface Complex.
Die Objekte dieser Klassen können einer Variable vom Typ
Complex zugewiesen werden.
Die Variable c kann daher auf unterschiedliche Objekte zeigen
– Inklusionspolymorphismus.
Programmiermethodik - Vererbung und Polymorphismus
22
Inklusionspolymorphismus
• Einer Variable können Objekte unterschiedlichen Typs zugeordnet
werden.



Typ der Variable beschreibt nur Schnittstelle.
Objekte, deren Klassen die Schnittstellen erfüllen, können zugewiesen werden.
Beim Aufruf einer Operation (zur Laufzeit) wird entsprechende Methode
ausgewählt (abhängig vom Objekt).
• Späte Bindung (dynamisches Binden)




Im Hauptprogramm wird zufällig eine Implementierung ausgewählt.
Wie wird die richtige Methode gefunden?
Zur Laufzeit wird von der JVM abhängig vom momentan zugewiesenen Objekt die
entsprechende Methode aufgerufen – dynamisches Binden.
Methodenaufruf wird abhängig vom Kontext in unterschiedliche Abläufe
umgesetzt.
Complex c1 = new Polar (2, 0);
Complex c2 = new Cartesian(0, 1);
c1.multiply(c2);
c2.multiply(c1);
Programmiermethodik - Vererbung und Polymorphismus
23
Statischer/Dynamischer Typ
Statischer Typ
• Typ der Variable laut Deklaration
• Bestimmt, welche Objektvariablen und Methoden
angesprochen werden können.
• Kompatibilitätsüberprüfung
Dynamischer Typ
• Typ zur Laufzeit (abhängig vom tatsächlich
zugewiesenen Objekt)
• Kann sich nach jeder (gültigen) Zuweisung ändern.
• Er bestimmt, welche Methoden wirklich aufgerufen
werden.
Programmiermethodik - Vererbung und Polymorphismus
24
Beispiel dynamischer Typ
Complex c = new Polar (2, 0);
c = new Cartesian(2, 0);
c = Math.random() > 0.5 ? c : new Polar(1, 1);
c = c.multiply(c);
Programmiermethodik - Vererbung und Polymorphismus
25
Mehrfache Implementierung
• Eine Klasse kann mehrere Interfaces implementieren (und
somit alle Methoden in den Interfaces implementieren).
• Mehrere Interfaces können die gleiche Methode
vorschreiben (gleiche Signatur).
• Die Klasse, die diese Interfaces implementiert, muss die
Methode nur einmal implementieren.
• Erben mehrerer abstrakter Klassen nicht möglich!
Programmiermethodik - Vererbung und Polymorphismus
26
Beispiel (mehrfache Implementierung)
public interface Printable {
String toString();
}
public class Cartesian implements Complex, Printable{
//methods for interface Complex as before
public String toString(){
return(this.real + " + " + this.imag + "i");
}
}
Programmiermethodik - Vererbung und Polymorphismus
27
Beispiele
• Stack.java
• Container.java
• Iterator.java,
• ArrayStack.java (ArrayIterator.java)
• StackContainerTest.java
Programmiermethodik - Vererbung und Polymorphismus
28
Ableiten (bei Interfaces)
• Ein Interface kann von einem anderen Interface abgeleitet
werden.
• Es wird das Schlüsselwort extends verwendet.
• Ein Interface kann mehrere Super-Interfaces haben.
• Das Interface übernimmt alles aus den Super-Interfaces und
kann zusätzliche Methoden und Konstanten hinzugeben.
Programmiermethodik - Vererbung und Polymorphismus
29
Beispiel
public interface Iterator {
boolean hasNext() ; //is there a next element?
String next( ) ; // give me next element
}
public interface RemovableIterator extends Iterator {
void remove() ;
// remove last element that was returned by next()
// from container
// automatically inherits methods from Iterator
}
Siehe auch LinkedList.java
• Programmiermethodik - Vererbung und Polymorphismus
• 30
Konstanten
• In Interfaces können Konstanten deklariert werden.
• Kostanten können auch weitervererbt werden.
• Wenn eine Klasse ein Interface mit Konstanten
implementiert, dann übernimmt sie diese Konstanten!
• Wird normalerweise nicht empfohlen!

Sollte in einer sauberen Implementierung vermieden werden
(Mischung Implementierung und Spezifikation)!
Programmiermethodik - Vererbung und Polymorphismus
31
Beispiel (schlecht!)
public interface Grundfarben {
int ROT = 1, GRUEN = 2, BLAU = 3;
}
public interface Sockenfarben extends Grundfarben {
int SCHWARZ = 10, LILA = 11;
}
public interface Hosenfarben extends Grundfarben {
int LILA = 11, SCHWARZ = 20, BRAUN = 21;
}
public interface Allefarben extends Sockenfarben, Hosenfarben {
int BRAUN = 30;
}
public class A implements Allefarben { }
Ausgabe:
1
1
20
1
1
20
public class InterfaceTest {
private InterfaceTest () { }
public static void main( final String [] args ) {
System.out.println(Sockenfarben.ROT);
System.out.println(Allefarben.ROT);
System.out.println(Hosenfarben.SCHWARZ);
// System.out.println(Allefarben.SCHWARZ);
Funktioniert nicht!
// System.out.println(Allefarben.LILA);
Funktioniert nicht!
A a = new A();
System.out.println(a.ROT);
System.out.println(A.ROT);
System.out.println(((Hosenfarben) a).SCHWARZ);
SCHWARZ
}
}
Programmiermethodik - Vererbung und Polymorphismus
und LILA sind
2 mal vorhanden!
32
Einsatz von Interfaces
• Erlauben die isolierte Entwicklung von Implementierungen.
• Anwendungen können nur auf Interfaces aufbauen.


Anwendung deklariert Variablen vom Interface-Typ.
Zukünftige Klassen, die das Interface implementieren, können sofort
in die Anwendung eingebunden werden.
• Leere Interfaces

Marker-Interfaces (werden noch besprochen)
Programmiermethodik - Vererbung und Polymorphismus
33
Vererbung der Implementierung in Java
Vererbung und Interfaces
• Ein Interface fixiert gemeinsame Eigenschaften von Klassen.


Klassen erfüllen den gleichen Zweck (im Interface angegeben).
Sind ansonsten unabhängig.
• Bei vielen Klassen beruht die Verwandtschaft nicht nur auf
gleichen Eigenschaften sondern auf Erweiterung und
Modifikation von Eigenschaften.
Programmiermethodik - Vererbung und Polymorphismus
35
Vererbung der Implementierung (allgemein)
• Unterklassen erben die in den Oberklassen bereits
implementierte Funktionalität.
• Public und im gleichen Paket
• Unterklassen erben



Verpflichtungen
Alle Methoden
Alle Daten
Sofern diese zur Schnittstelle der
Oberklasse gehören oder durch
Sichtbarkeitsregeln freigegeben wurden.
• Funktionalität kann komplett übernommen werden oder von
der Unterklasse verändert/erweitert werden.
Überschreiben
Programmiermethodik - Vererbung und Polymorphismus
36
Überschreiben (allgemein)
• Unterklasse implementiert eine Operation, für die es bereits
in einer Oberklasse eine Methode gibt.
• Wird die Methode auf ein Exemplar der Unterklasse
aufgerufen, dann wird die überschriebene Implementierung
aufgerufen.



Hängt nicht vom Typ der Variable ab, über die das Objekt referenziert
wird.
Entscheidend ist der Typ des Objekts.
Polymorphie!
• Überschriebene Methode kann


eigene Implementierung haben oder
zusätzlich auf geerbte Implementierung zugreifen.
Programmiermethodik - Vererbung und Polymorphismus
37
Überschreiben (speziell)
• Geschützte Methoden (protected)



Gehören nicht zur Schnittstelle, nur in Unterklassen und im gleichen
Paket sichtbar.
Unterstützen Methoden der Schnittstelle.
Können in Unterklassen verwendet und überschrieben werden.
• Überschreiben verhindern (final)


Oberklasse will eine bestimmte Funktionalität erzwingen.
Unterklasse darf nicht überschreiben (z.B. um bestimmte Verträge
einzuhalten).
Programmiermethodik - Vererbung und Polymorphismus
38
Beispiel Fahrzeugverwaltung
• KFZ



Kennzeichen
Standort
Methode zur Ausgabe der KFZ-Daten
• LKW





Kennzeichen
Standort
Ladung
Methode zur Ausgabe der KFZ-Daten
Methode zum Ändern der Ladung
Programmiermethodik - Vererbung und Polymorphismus
39
Beispiel (schlechte Lösung)
• Vehicle1.java
• Truck1.java
• VehicleTest1.java
Programmiermethodik - Vererbung und Polymorphismus
40
Vererbung in Java
• Eine Klasse B kann die Subklasse (Unterklasse, abgeleitete
Klasse) einer anderen Klasse A (Superklasse, Oberklasse,
Basisklasse) sein.
• Eine Subklasse erbt alle Objektvariablen und Methoden der
Superklasse.
• Eine Subklasse kann weitere Objektvariablen deklarieren und
Methoden implementieren.
• Ein Objekt der Subklasse ist auch ein Objekt der Superklasse.
• Java unterstützt nur Einfachvererbung (nur eine
Superklasse)!
Programmiermethodik - Vererbung und Polymorphismus
41
Beispiel (mit Vererbung)
• Vehicle2.java
• Truck2.java
• VehicleTest2.java
Programmiermethodik - Vererbung und Polymorphismus
42
Syntax
• Zusatz „extends Vehicle2“ lässt die Klasse Truck2 von
der Klasse Vehicle2 erben.
• Bestandteile der Klasse Vehicle2 werden in der Klasse Truck2
eingeblendet (sind dort vorhanden).

Aber nicht alles ist sichtbar (z.B. number, location sind als
private deklariert)!
• Methode getInfo wird geerbt und kann in der Klasse
Truck2 aufgerufen werden.
Programmiermethodik - Vererbung und Polymorphismus
43
Konstruktoren bei der Vererbung
• Konstruktoren werden nicht vererbt.
• Jeder Konstruktor einer Subklasse muss zuerst einen
Superklassen-Konstruktor aufrufen (Initialisierung der
Superklasse)!
• Wenn nichts angegeben wird, dann ruft ein Konstruktor den
Default-Konstruktor in der Superklasse auf.
• Wenn dieser nicht existiert?


Entweder in der Superklasse implementieren.
Einen anderen Konstruktor in der Superklasse explizit aufrufen.
Programmiermethodik - Vererbung und Polymorphismus
44
Expliziter Aufruf
• Der Default-Konstruktor kann auch explizit mit super();
aufgerufen werden (redundant!).
• Wie bei this() und seinen Varianten kann man auch bei
super() zu allen möglichen Konstruktoren eine Verbindung
herstellen.

Im Beispiel wird mit super(name,address); der entsprechende
Konstruktor in Vehicle aufgerufen.
• Folgende Einschränkungen existieren:



Der super-Aufruf darf nur einmal vorkommen.
Der super-Aufruf muss als erste Anweisung auftreten.
this()- Aufrufe und super()- Aufrufe können nicht gleichzeitig
verwendet werden (immer erster Aufruf!).
Programmiermethodik - Vererbung und Polymorphismus
45
Zugriffsschutz mit protected
• Im Beispiel sind number und location mit private
gekennzeichnet.

In Truck2 kann man nicht direkt darauf zugreifen.
• Mit protected markierte Objektvariablen und
Methoden stehen allen Subklassen zur Verfügung.



Sind in den Subklassen sichtbar und in Klassen des gleichen
Pakets.
Sichtbarkeit erstreckt sich auch über mehrere Stufen einer
Vererbungshierarchie.
Wie bei private gibt es eine Unterscheidung zwischen
klassenbasierter und objektbasierter Definition.
 In Java klassenbasiert!
Programmiermethodik - Vererbung und Polymorphismus
46
Überschreiben von Methoden
• Eine Klasse kann Methoden, die sie von der Superklasse erbt,
neu implementieren (Überschreiben).
• Folgende Regeln gelten dabei:

Name und Parameterliste der überschriebenen Methode müssen
exakt übernommen werden.
 Ansonsten: Überladen (auch in Subklassen möglich)



Der Zugriffsschutz darf gelockert werden (z.B. protected in
public).
Der Ergebnistyp darf vom Ergebnistyp der zu überschreibenden
Methode abgeleitet werden.
Der Rumpf kann komplett ersetzt werden.
Programmiermethodik - Vererbung und Polymorphismus
47
Beispiele
• Zugriff mittels protected Attributen  widerspricht Prinzip
der Datenkapselung!



Vehicle3.java
Truck3.java
VehicleTest3.java
• bessere Lösung mit Zugriff mittels protected Gettern:



Vehicle4.java
Truck4.java
VehicleTest4.java
Programmiermethodik - Vererbung und Polymorphismus
48
Zugriff auf die Superklasse
• super kann auch in normalen Methoden eingesetzt
werden.

Wenn man eine Methode nur erweitern möchte.
• super.m() ruft die entsprechende Methode m() in der
direkten Superklasse auf.
• Eine weitere Verkettung ist nicht möglich!

d.h. super.super.m() ist nicht möglich.
• m() darf nicht private sein.
• Kann auch bei Objektvariablen eingesetzt werden.
Programmiermethodik - Vererbung und Polymorphismus
49
Beispiel (3. Version)
• bessere Lösung mittels super:



Vehicle5.java
Truck5.java
VehicleTest5.java
Programmiermethodik - Vererbung und Polymorphismus
50
Polymorphismus (Wiederholung)
• Es ist erlaubt, dass einer Variable oA vom Typ A ein Objekt oB
einer beliebigen Subklasse B zugewiesen werden darf.

oA=oB ist immer erlaubt (Ersetzbarkeitsprinzip).
• oB=(B) oA ist nur zulässig, wenn oA auf ein B-Objekt zeigt
(wenn der Typ von OA also OB ist).



Expliziter Cast notwendig.
Wird als Downcast bezeichnet.
Downcast ist problematisch!
 Verletzt Prinzip der Trennung der Schnittstelle von der Implementierung.
 Kann meist mit Hilfe der dynamischen Polymorphie und dem Prinzip der
Ersetzbarkeit umgangen werden.
Programmiermethodik - Vererbung und Polymorphismus
51
instanceof - Operator
• Objektvariablen sind polymorph.


Sie haben einen statischen Typ (Deklaration, z.B. Complex).
Sie haben eine aktuelle Klassenzugehörigkeit (dynamischer Typ, z.B.
Polar).
• Der dynamische Typ kann mit instanceof abgefragt
werden.



Vererbung muss aber berücksichtigt werden.
Erbt eine Klasse B von einer Klasse A, dann ist ein entsprechendes
Exemplar der Klasse B auch Exemplar der Klasse A, die Umkehrung
gilt aber nicht!
instanceof sollte nur in Ausnahmefällen eingesetzt werden.
Programmiermethodik - Vererbung und Polymorphismus
52
Beispiel (Polymorphie, Typtest)
• VehicleTest5b.java
Programmiermethodik - Vererbung und Polymorphismus
53
final bei Methoden und Klassen
• Wird eine Methode zusätzlich mit dem Schlüsselwort final
versehen,


dann kann die Methode in einer Subklasse nicht mehr überschrieben
werden
und wird dynamisches Binden unterbunden.
• Man kann auch eine Klasse mit final versehen.
Es kann keine Subklasse gebildet werden.
 Alle Methoden sind automatisch final.
 Beispiele (Performance als Grund für final)

 String,
 Stringbuffer,
 StringBuilder, ….
Programmiermethodik - Vererbung und Polymorphismus
54
Kovarianz, Kontravarianz, Invarianz
• Was darf beim Überschreiben verändert werden?
• Kovarianz (entlang der Vererbungsrichtung)

Redefinition von Parameter- und Ergebnistypen mit Subtypen
• Kontravarianz (entgegen der Vererbungsrichtung)

Redefinition von Parameter- und Ergebnistypen mit Supertypen
• Invarianz

Typen bleiben gleich
• Java (seit Version 1.5)


Kovarianz bei Ergebnistypen
Sonst Invarianz
Programmiermethodik - Vererbung und Polymorphismus
55
Kovarianter Ergebnistyp
• Kovariante Ergebnistypen erlauben jeden kompatiblen
Ergebnistyp bei der Redefinition ererbter Methoden und bei
der Implementierung von Interfacemethoden.
• Beispiel
public class A{
public A get(){...}
}
public class B extends A{
public B get(){...}
}
public class C extends B{
public C get(){...}
}
Programmiermethodik - Vererbung und Polymorphismus
56
Vererbung der Implementierung
• Vorteil der Vererbung der Implementierung



Methoden müssen nicht neu implementiert werden.
Redundanzen im Quellcode werden vermieden.
DRY!
• Aber


Vererbung legt eine starre Struktur fest.
Erweiterungen sind mit Aufwand verbunden.
Programmiermethodik - Vererbung und Polymorphismus
57
Probleme
• Klasse B kann Funktionalität der Klasse A nutzen durch:


Vererbung (B erbt von A)
Beziehung (Assoziation zwischen B und A)
• Falle



Vererbung erscheint einfacher.
Aber nicht immer sinnvoll.
Prinzip der Ersetzbarkeit sollte immer gelten (wo
Supperklasse erwartet wird, kann auch Subklasse eingesetzt
werden)!
Programmiermethodik - Vererbung und Polymorphismus
58
Bsp: Einhaltung des Prinzips der Ersetzbarkeit
• Container bietet Einfügen und Iterator an

Bedingungen: Iterator muss über alle Elemente iterieren, die bislang
eingefügt (und nicht entfernt) wurden
• Klasse ArrayStack implementiert Container-Schnittstelle
• Klasse LinkedList implementiert Container-Schnittstelle
Programmiermethodik - Vererbung und Polymorphismus
59
Verletzung des Prinzips der Ersetzbarkeit
public class Rectangle {
double width;
double height;
public void scaleWidth ( double factor) { . . . }
public void scaleHeight ( double factor) { . . . }
public void scale (double factor) { . . . }
. . .
}
public class Square extends Rectangle {
// invariant : width = h e i g h t
}
• Problem: Quadrat kann nicht wie Rechteck benutzt werden; Beispiel:
Rectangle r = new Square(5.0);
r.scaleWidth(2);
 Invariante wird verletzt
Programmiermethodik - Vererbung und Polymorphismus
scaleWidth()  Invariante nicht mehr erfüllt
 Funktion kann nicht zur Verfügung gestellt
werden
 Prinzip der Ersetzbarkeit?
60
Problem der instabilen Basisklasse
• Falls das Prinzip der Ersetzbarkeit gilt?


Alles ok?
Gilt das auch in der Zukunft?
• Problem der instabilen Basisklasse (Fragile Base Class
Problem).
Anpassungen an der Basisklasse können zu unerwartetem Verhalten
von abgeleiteten Klassen führen.
 Wartung von Systemen, die nur Vererbung der Implementierung
benutzen, ist schwierig.

• Sind spätere Änderungen an der Basisklasse sehr
wahrscheinlich:


Vererbung der Spezifikation
Wenn man Redundanzen vermeiden möchte - Delegation
Programmiermethodik - Vererbung und Polymorphismus
61
Dynamisches Binden
• Beim Übersetzen von Methodenaufrufen prüft der Compiler
den statischen Typ des Zielobjekts.


Die Variable v in typeTest(Vehicle v) hat den Typ Vehicle.
Die Klasse Vehicle5 definiert die Methode getInfo() und daher
wird der Aufruf akzeptiert.
• Zur Laufzeit wird der Methodenaufruf dynamisch gebunden.
Der aktuelle Typ von v wird herangezogen um die tatsächliche
Methode zu bestimmen.
 Wenn die Methode nicht überschrieben wurde, wird die
entsprechende Methode aus der Superklasse aufgerufen.

• Beispiel: typeTest(new Truck5(...)) wird getInfo () aus Truck5
ausführen
Programmiermethodik - Vererbung und Polymorphismus
62
Statisches Binden
• In bestimmten Situationen werden Methoden statisch (und
nicht dynamisch) gebunden.

Statische Methoden
 Gehören zu einer Klasse und nicht zu einem Objekt.

Konstruktoren
 Objekt muss erst vom Konstruktor erzeugt werden.

Private Methoden
 Sind in der Subklasse nicht sichtbar.
 Eine neue Definition einer privaten Methode ist keine Redefinition!
• Binden von Datenelementen



Datenelemente werden statisch gebunden.
Beim Zugriff wird der statische Typ herangezogen.
Datenelemente werden aber geerbt.
Programmiermethodik - Vererbung und Polymorphismus
63
Beispiel (statische Datenelemente)
public class Base {
protected int data = 1;
}
public class Sub extends Base {
protected int data = 2;
}
Ausgabe:
1
2
public class Sub2 extends Sub {
}
public class Test {
public static void main(final String[] args) {
final Base x = new Sub();
final Sub2 s = new Sub2();
System.out.println(x.data);
System.out.println(s.data);
}
}
Programmiermethodik - Vererbung und Polymorphismus
64
Delegation
• Ein Objekt setzt eine Operation so um, dass der Aufruf der
Operation an ein anderes Objekt delegiert (weitergereicht)
wird.
• Verantwortung, eine Implementierung für eine bestimmte
Schnittstelle bereitzustellen, wird an ein Exemplar einer
anderen Klasse delegiert.
• Vorteil



Kann mit der Vererbung der Spezifikation gemeinsam benutzt werden
(Quellcode einsparen).
Auch ohne Mehrfachvererbung kann die Funktionalität von mehreren
Klassen benutzt werden.
Dynamisch (Delegat kann zur Laufzeit geändert werden).
• Beispiel Brunnen: LoggingWell3.java, WellTest.java
Programmiermethodik - Vererbung und Polymorphismus
65
„is-a“ vs. „has-a“
• „B ist ein A“ → B wird von A abgeleitet.
• „B enthält ein A“→ B definiert eine Objektvariable vom
Typ A.
• Beispiel

2 Klassen Dreieck und Punkt (has-a)
 Dreieck ist ein Punkt – Falsch
 Dreieck enthält einen Punkt – Richtig
 Klasse Dreieck verwendet daher die Klasse Punkt (Objektvariable vom
Typ Punkt).

2 Klassen Dreieck und Polygon (is-a)
 Dreieck ist ein Polygon – Richtig
 Dreieck enthält ein Polygon – Falsch
 Dreieck wird von Polygon abgeleitet.
Programmiermethodik - Vererbung und Polymorphismus
66
Abstraktionsebenen
• Vererbung einsetzen, wenn Superklasse und Subklasse
konzeptionell auf unterschiedlichen Abstraktionsebenen
stehen.

Klassenname ist umgangssprachlich ein Oberbegriff des anderen
Klassennamens.
• Beispiel
Polygon
Quadrangle
Rectangle
Programmiermethodik - Vererbung und Polymorphismus
Square
67
Abstrakte Klassen
Abstrakte Klassen
• Konkrete Superklassen und Interfaces bilden zwei Extreme.
• Abstrakte Klassen bilden einen Mittelweg.



Enthalten Objektvariablen.
Enthalten vollständige Methoden.
Enthalten Schnittstellen (abstrakte Methoden).
• Eine abstrakte Klasse wird mit dem Schlüsselwort abstract
markiert.



Zusätzlich werden die abstrakten Methoden mit abstract
gekennzeichnet.
Es kann auch keine abstrakten Methoden in einer abstrakten Klasse
geben.
Wenn eine Klasse ein Interface nicht vollständig implementiert, dann
muss sie auch eine abstrakte Klasse sein.
Programmiermethodik - Vererbung und Polymorphismus
69
Vererbung bei abstrakten Klassen
• Von einer abstrakten Klasse können keine Objekte angelegt
werden.
• Eine Subklasse muss alle abstrakten Methoden
implementieren, damit man von dieser Subklasse Objekte
anlegen kann.
• Implementiert eine Subklasse nur einen Teil (oder keine) der
abstrakten Methoden, dann ist sie auch eine abstrakte
Klasse.
• In einer Subklasse können neue Methoden definiert und
Methoden überschrieben werden.
• Auch super kann verwendet werden.
• Beispiel

Siehe nächste Folie
Programmiermethodik - Vererbung und Polymorphismus
70
Abstrakte Klassen
public abstract class DefaultStack implements Stack {
// provide default implementation for peek
public Object peek() {
Object o = this.pop();
this.push(o);
return o;
}
// leave remaining stack operations open
// for concrete classes
public abstract Object pop();
public abstract boolean isEmpty();
public abstract void push(Object obj);
}
Programmiermethodik - Vererbung und Polymorphismus
71
Abstrakte Klasse - Interface
• Unterschiede



Die abstrakten Methoden können auch den Zugriffsschutz
protected und default haben (in einem Interface ist nur public
erlaubt).
Können Objektvariablen definieren (nicht nur Konstanten).
Können Konstruktoren enthalten, die von den Subklassen benutzt
werden.
• Rein abstrakte Klassen sind möglich.


Keine Objektvariablen
Nur abstrakte Methoden
• Wozu dann Interfaces?

In Java gibt es bei Klassen nur Einfachvererbung!
Programmiermethodik - Vererbung und Polymorphismus
72
Subtyping und Subclassing
Subtyping
• Wenn eine Klasse ein Interface
implementiert (von diesem Interface „erbt“).
• Es wird nur der Typ „geerbt“
Subclassing
• Wenn eine Klasse von einer andere Klasse
erbt.
• Es wird die Implementierung geerbt.
Programmiermethodik - Vererbung und Polymorphismus
73
Varianten der Vererbung (Zusammenfassung)
Reine Vererbung der Spezifikation
• Schnittstellen-Klassen (Interfaces in Java)
Vererbung der Spezifikation und
Implementierung
• Normalfall (auch in Java)
• Unterklasse erbt Spezifikation und Implementierung.
Reine Vererbung der Implementierung
• Unterklasse übernimmt nur Implementierung, nicht
die Spezifikation.
• Für interne Nutzung (z.B. private Vererbung in C++)
Programmiermethodik - Vererbung und Polymorphismus
74
Die Klasse Object
Die Wurzelklasse Object
• Jede Klasse, die von keiner Klasse erbt, erbt automatisch von
der Wurzelklasse Object.

Folgende Definitionen sind äquivalent:
public class className {…}
public class className extends Object {…}
• Damit werden alle Klassen direkt oder indirekt von Object
abgeleitet.
Programmiermethodik - Vererbung und Polymorphismus
76
Vordefinierte Methoden (1)
• Object bietet einige Methoden an, die an jede Java-Klasse
vererbt werden.
• Beispiele (vereinfacht !)
public String toString()
 Liefert eine lesbare Repräsentation des Objekts (siehe getInfo() im Beispiel).
public boolean equals(Object x)
 Prüft ob das Zielobjekt und x gleich sind.
public int hashCode() …
 Liefert eine Kennnummer (Hashcode) des Objekts.
protected Object clone()
 Liefert eine Kopie des Objekts.
protected void finalize() …
 Wird vom Garbage Collector aufgerufen.
 Problematisch
Programmiermethodik - Vererbung und Polymorphismus
77
Vordefinierte Methoden (2)
• Methoden (gesamte Information, wird in den folgenden
Vorlesungen noch teilweise erklärt):
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj) { ... }
protected native Object clone() throws
CloneNotSupportedException;
public String toString() { ... }
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws
InterruptedException;
public final void wait(long timeout, int nanos) throws
InterruptedException { ... }
public final void wait() throws InterruptedException { ... }
protected void finalize() throws Throwable { ... }
Programmiermethodik - Vererbung und Polymorphismus
78
Implementierungen in der Klasse Object
• Minimale Implementierung
• Die Methoden sollten in jeder Klasse entsprechend
überschrieben werden.
• Wenn diese Methoden nicht überschrieben werden, wird die
minimale Implementierung aus Object verwendet.
• Beispiele

toString gibt den Namen der Klasse zusammen mit dem Hashcode
aus:
public String toString() {
return getClass().getName() + "@" +
Integer.toHexString(hashCode());
}

equals vergleicht nur die Referenzen:
public boolean equals(Object obj) {
return (this == obj);
}
 usw.
Programmiermethodik - Vererbung und Polymorphismus
79
equals
• Default-Implementierung vergleicht nur Referenzen.
• Eine korrekte Implementierung erfüllt:

Reflexivität
 x.equals(x) → true

Symmetrie
 x.equals(y) == y.equals(x)

Transitivität
 x.equals(y) → true, y.equals(z) → true dann gilt auch x.equals(z)
→ true

Konsistenz
 Zwei Objekte müssen bei wiederholten Aufrufen von equals immer das gleiche
Ergebnis liefern, so lange sie sich nicht verändert haben.

Für alle Objekte x, die nicht gleich null sind, gilt:
 x.equals(null) → false
Programmiermethodik - Vererbung und Polymorphismus
80
Probleme bei instanceof
• Zwei Objekte voneinander abgeleiteter Typen liefern kein
symmetrisches Ergebnis:
Person p = new Person("Willi","Weg 3");
Student s = new Student("Maja","Allee 2",200);
System.out.println(s instanceof Person);// true
System.out.println(p instanceof Student); // false
Programmiermethodik - Vererbung und Polymorphismus
81
Typobjekte
• Typobjekte

Java Reflection – siehe Entwurf von Softwaresystemen.
• Jedem Typ ist ein eindeutiges Typobjekt zugeordnet.
• Type.class

System.out.println(String.class)
liefert „class java.lang.String“
• Das Typobjekt eines Objekts obj kann mit
obj.getClass() ermittelt werden (auch eine Methode der
Klasse Object).

System.out.println("Hello".getClass());
Liefert „class java.lang.String“
Programmiermethodik - Vererbung und Polymorphismus
82
hashcode
• Für jedes Objekt sollte eine eindeutige Kennnummer (nicht
immer möglich) produziert werden.
• Wird vor allem im Collection-Framework (z.B. HashMap; wird
noch besprochen) benutzt.
• Anforderungen:



Hashcode muss immer gleich bleiben, solange sich das Objekt nicht
ändert.
Wenn zwei Objekte gemäß equals gleich sind, müssen sie auch den
gleichen Hashcode produzieren.
Die Umkehrung gilt nicht, d.h. zwei Objekte können den gleichen
Hashcode haben, aber verschieden sein.
Programmiermethodik - Vererbung und Polymorphismus
83
hashcode (Berechnung)
• Integervariable result mit einem Wert > 0 belegen.
• Für jede Objektvariable a (die auch von equals verwendet wird) im
Objekt berechne abhängig vom Typ:







boolean: (a ? 1 : 0)
byte, char, short, int: (int) a
long: (int) (a^(a>>>32))
float: Float.floatToIntBits(a)
double: Double.doubleToIntBits(a)
Objektreferenzen: Wenn null dann 0, ansonsten Aufruf von hashcode().
Array: Benutze Arrays.hashcode() oder behandle jedes Element wie eine
eigene Objektvariable.
• Nachdem für eine Objektvariable der Hashcode c berechnet wurde,
berechne (unter Benützung von prime, prime meist 31).

result = prime*result+c
• Gib result zurück.
Programmiermethodik - Vererbung und Polymorphismus
84
hashcode und equals
• equals und hashCode hängen zusammen und sollten
immer gemeinsam überschrieben werden.
• equals und hashCode sollten immer die gleichen
Objektvariablen verwenden.
• Man sollte immer die hashCode-Methode von Referenzen
verwenden (falls implementiert).
Programmiermethodik - Vererbung und Polymorphismus
85
clone
• Ein Kopier-Konstruktor eignet sich zum Kopieren eines
Objekts ohne Vererbung.
• Kopieren bei einem dynamischen Typ kann nur durch eine
dynamisch gebundene Methode erfolgen – clone-Methode.
• clone hat den Zugriffsschutz protected.


Damit kann die Methode nicht von außen aufgerufen werden, wenn
sie nicht überschrieben wird.
Beim Überschreiben muss der Zugriffsschutz gelockert werden
(public).
Programmiermethodik - Vererbung und Polymorphismus
86
Regeln für clone
• Eine Klasse muss




das Interface Cloneable implementieren,
eine eigene öffentliche Methode clone() implementieren,
in clone eine Kopie des Superklassenobjekts mit super.clone()
erzeugen,
in clone alle Datenelemente veränderlicher Klassen einzeln mit
clone-Aufrufen auf diese Objekte kopieren.
• clone kann nur verwendet werden, wenn jede verwendete
Klasse clone korrekt implementiert.
• Beispiele folgen noch.
Programmiermethodik - Vererbung und Polymorphismus
87
Herunterladen