1 / 41 Einstieg in die Informatik mit Java Vererbung Gerd Bohlender Institut für Angewandte und Numerische Mathematik
Gliederung 2 / 41 1 Überblick: Vererbung 2 Grundidee Vererbung 3 Verdeckte Variablen 4 Verdeckte Methoden 5 Konstruktoren und Vererbung 6 Klassen und final 7 Zugriffsrechte und Vererbung 8 Abstrakte Methoden und Klassen
Gliederung 3 / 41 1 Überblick: Vererbung 2 Grundidee Vererbung 3 Verdeckte Variablen 4 Verdeckte Methoden 5 Konstruktoren und Vererbung 6 Klassen und final 7 Zugriffsrechte und Vererbung 8 Abstrakte Methoden und Klassen
4 / 41 Überblick: Vererbung In diesem Kapitel betrachten wir die Konzepte der Vererbung und Polymorphie. Eigenschaften Auf der Grundlage einer bestehenden Klasse wird eine neue Klasse definiert. Die Komponenten (Attribute, Methoden) der bestehenden Klasse werden übernommen. Neue Komponenten können hinzugefügt werden. Bestehende Methoden können angepasst werden. Bei Instanzmethoden wird die am besten passende Methode zur Laufzeit ausgewählt (Polymorphie).
Gliederung 5 / 41 1 Überblick: Vererbung 2 Grundidee Vererbung 3 Verdeckte Variablen 4 Verdeckte Methoden 5 Konstruktoren und Vererbung 6 Klassen und final 7 Zugriffsrechte und Vererbung 8 Abstrakte Methoden und Klassen
Grundidee Vererbung 6 / 41 Durch Vererbung werden von einer allgemeinen Klasse (Superklasse, Basisklasse) spezielle Klassen (Subklassen, abgeleitete Klassen) abgeleitet. Diese erben die Komponenten der Superklasse und besitzen ggfs. weitere Methoden und Variablen. Syntax class Subklasse extends Superklasse { / / eigene Methoden und Variablen
7 / 41 Grundlagen In Java kann eine Subklasse nur von einer Superklasse abgeleitet werden. Es ist also keine Mehrfachvererbung möglich (im Gegensatz zu manchen anderen Programmiersprachen). Es darf über mehrere Stufen hinweg vererbt werden. Man spricht dann von indirekten Sub und Superklassen, andernfalls von direkten. Alle Klassen ohne Angabe von extends sind abgeleitet von der Superklasse Object. Konstruktoren, static Initialisierer und private Komponenten werden nicht vererbt.
Grundlagen 8 / 41 Beispiel Student matrikelnr... Kursteilnehmer bearbaufgaben... Person name vorname... Beamter dienstalter gehaltsstufe...
Beispiel, Instanzvariablen 9 / 41 class Person { S t r i n g name, vorname ; / / gemeinsame Eigenschaften class Student extends Person { i n t m a t r i k e l n r ; / / z u s a e t z l i c h e Eigenschaften class Beamter extends Person { i n t d i e n s t a l t e r ; / / z u s a e t z l i c h e Eigenschaften S t r i n g g e h a l t s s t u f e ; class Kursteilnehmer extends Student { i n t bearbaufgaben ; / / z u s a e t z l i c h e Eigenschaften
Beispiel, Basisklasse Person 10 / 41 Dazu kommen natürlich die passenden Methoden und Konstruktoren, z.b. für die Basisklasse: class Person { S t r i n g name, vorname ; / / gemeinsame Eigenschaften Person ( S t r i n g n, S t r i n g v ) { / / Konstruktor name = n ; vorname = v ; void nameausgeben ( ) { / / Methode System. out. p r i n t l n ( vorname + + name ) ;
Beispiel, abgeleitete Klasse Student 11 / 41... und für die abgeleitete Klasse Student: class Student extends Person { i n t m a t r i k e l n r ; / / z u s a e t z l i c h e Eigenschaften Person ( S t r i n g n, S t r i n g v, i n t m) { / / Konstruktor name = n ; vorname = v ; m a t r i k e l n r = m; void allesausgeben ( ) { / / Methode nameausgeben ( ) ; System. out. p r i n t l n ( M a t r i k e l n r : + m a t r i k e l n r ) ;
12 / 41 Zugriffsrechte Neben den im Kapitel zu Klassen und objektorientierter Programmierung schon erwähnten Modifizierern existiert zusätzlich der Modifizierer protected. Der Zugriff auf die entsprechende Komponente ist dabei im gleichen Paket (d.h. im allgemeinen im gleichen Verzeichnis) und in allen Subklassen erlaubt. Damit ergibt sich die folgende Hierarchie an Zugriffsrechten: public > protected > (default) > private Anmerkung Zugriffsrechte werden zur Übersetzungszeit geprüft, nicht erst zur Laufzeit.
Gliederung 13 / 41 1 Überblick: Vererbung 2 Grundidee Vererbung 3 Verdeckte Variablen 4 Verdeckte Methoden 5 Konstruktoren und Vererbung 6 Klassen und final 7 Zugriffsrechte und Vererbung 8 Abstrakte Methoden und Klassen
Verdeckte Variablen 14 / 41 Gleichnamige Variablen in Sub und Superklasse mit gleichem oder verschiedenem Typ sind erlaubt. Die Variablen aus der Superklasse bleiben erhalten, sie werden lediglich verdeckt, d.h. der direkte Zugriff aus der Subklasse heraus ist nicht möglich. Abhilfe schafft der Zugriff mit... Syntax Klassenname.Variablenname super.variablenname ((Superklasse)Instanz).Variablenname bei Klassenvariablen bei Instanzvariablen und direkter Superklasse in beiden Fällen und auch bei indirekter Superklasse Achtung Zwischen Methodennamen und Variablennamen besteht kein Problem. Diese dürfen sowohl innerhalb einer Klasse als auch in Sub und Superklasse den gleichen Namen tragen!
Verdeckte Variablen, Beispiel 15 / 41 Beispiel class Super { i n t x = 1; i n t x ( ) { return 2; class Sub extends Super { i n t x = 3; i n t x ( ) { return 4; void i n f o ( ) { System. out. p r i n t l n ( + x + x ( ) + super. x + super. x ( ) ) ; public s t a t i c void main ( S t r i n g s ){ Sub i n s t a n z = new Sub ( ) ; i n s t a n z. i n f o ( ) ; / / e r g i b t 3412
Verdeckte Variablen, Beispiel Alternative für Instanzvariablen Anstatt super.x kann man für Instanzvariablen auch die Typecast-Notation ((Super) this).x verwenden! Hierbei ist Super der Name der Superklasse, im Gegensatz zum Wortsymbol super Achtung Bei Methoden hat die Typecast-Notation ((Super) this).x() nicht das erwartete Ergebnis! Dies wird im nächsten Abschnitt besprochen. Anmerkung: eine mehrfache Anwendung von super ist nicht erlaubt, z.b. ist super.super.x keine erlaubte Schreibweise für die Variable x aus der Großelterngeneration. 16 / 41
Gliederung 17 / 41 1 Überblick: Vererbung 2 Grundidee Vererbung 3 Verdeckte Variablen 4 Verdeckte Methoden 5 Konstruktoren und Vererbung 6 Klassen und final 7 Zugriffsrechte und Vererbung 8 Abstrakte Methoden und Klassen
18 / 41 Verdeckte Methoden, Polymorphie Methoden können auch im Zusammenhang mit Vererbung überladen werden, d.h. sie tragen den gleichen Namen, aber eine andere Signatur. Hat in der Subklasse eine Instanzmethode den gleichen Namen und die gleiche Signatur wie in der Superklasse, so wird bei einer Objektreferenz automatisch die Methode der Subklasse verwendet (Polymorphie). Der Zugriff auf die Methode der Superklasse erfolgt dann über super.methodenname Achtung Außerhalb der Subklasse ist ein Zugriff nicht möglich, da der Typ von Klassen dynamisch zur Laufzeit bestimmt wird (Polymorphie) und eine Referenz vom Typ der Superklasse auch auf eine Instanz der Subklasse verweisen darf!
Verdeckte Methoden 19 / 41 Beispiel class Basis { void i n f o ( ) { System. out. p r i n t l n ( Basis ) ; class A b g e l e i t e t extends Basis { void i n f o ( ) { System. out. p r i n t l n ( a b g e l e i t e t ) ; public s t a t i c void main ( S t r i n g s ){ A b g e l e i t e t a = new A b g e l e i t e t ( ) ; a. i n f o ( ) ; / / a b g e l e i t e t ( ( Basis ) a ). i n f o ( ) ; / / auch : a b g e l e i t e t A b g e l e i t e t b = new Basis ( ) ; / / Fehler! Basis b = new A b g e l e i t e t ( ) ; / / ok! b. i n f o ( ) ; / / a b g e l e i t e t
20 / 41 Konversionen ref Basis Abgeleitet zusätzliche Komponenten Damit gelten offenbar die folgenden Regeln für Konversionen zwischen Basisklasse und abgeleiteter Klasse: (1) Ein Objekt der abgeleiteten Klasse kann automatisch in ein Objekt der Basisklasse konvertiert werden, da es alle notwendigen Komponenten enthält (Up Cast). (2) Dagegen kann ein Objekt der Basisklasse nicht automatisch in ein Objekt der abgeleiteten Klasse konvertiert werden, da Komponenten fehlen. Ist es aber in Wirklichkeit ein Objekt der abgeleiteten Klasse, dann geht eine explizite Konversion mittels eines Down Cast.
Konversionen, Beispiel 21 / 41 Beispiel / / Konversion von Basis nach A b g e l e i t e t : Basis b = new Basis ( ) ; A b g e l e i t e t a = b ; / / Fehler! A b g e l e i t e t a = ( A b g e l e i t e t ) b ; / / Fehler! / / Konversion von A b g e l e i t e t nach Basis : A b g e l e i t e t a = new A b g e l e i t e t ( ) ; Basis b = a ; / / okay, / / i m p l i z i t e Konversion der Referenz A b g e l e i t e t c = ( A b g e l e i t e t ) b ; / / okay, / / b r e f e r e n z i e r t Objekt vom Typ A b g e l e i t e t
Polymorphe Methoden, Beispiel Beispiel: Polymorphe Methode info class Basis { void i n f o ( ) { System. out. p r i n t l n ( Basis ) ; class A b g e l e i t e t extends Basis { void i n f o ( ) { System. out. p r i n t l n ( a b g e l e i t e t ) ; class Haupt { public void s t a t i c main ( S t r i n g [ ] args ) { Basis [ ] a = { new A b g e l e i t e t ( ), new Basis ( ), new A b g e l e i t e t ( ) ; for ( i n t i =0; i <a. length ; i ++){ a [ i ]. i n f o ( ) ; / / e r g i b t : a b g e l e i t e t Basis a b g e l e i t e t 22 / 41
23 / 41 Polymorphie Polymorphie Der Typ der Klasse, zu der eine Instanzmethode gehört (im obigen Beispiel die Methode info()), wird erst zur Laufzeit bestimmt (späte Bindung, Polymorphie). Damit wird die optimal passende Version der Methode ausgeführt. Keine Polymorphie Bei Methoden mit den Wortsymbolen static (Klassenmethoden), final oder private erfolgt die Bestimmung der zuständigen Methode bereits zur Compilerlaufzeit (frühe Bindung) anhand des angegebenen Datentyps. Es tritt keine Polymorphie auf.
Gliederung 24 / 41 1 Überblick: Vererbung 2 Grundidee Vererbung 3 Verdeckte Variablen 4 Verdeckte Methoden 5 Konstruktoren und Vererbung 6 Klassen und final 7 Zugriffsrechte und Vererbung 8 Abstrakte Methoden und Klassen
Konstruktoren und Vererbung Konstruktoren werden nicht vererbt, allerdings kann der Konstruktor der direkten Superklasse aufgerufen werden. Syntax super(parameterliste); Der Aufruf muss als erste Anweisung im Konstruktor der Subklasse stehen. Da der Aufruf eines anderen Konstruktors der gleichen Klasse mittels this(); ebenfalls als erste Anweisung stehen muss, darf nur entweder super(); oder this(); verwendet werden. Achtung Nicht erlaubt ist der Aufruf der Konstruktors der Superklasse innerhalb von bedingten Anweisungen, Schleifen, usw., da dann der Aufruf nicht an erster Stelle erfolgt! 25 / 41
26 / 41 Konstruktoren und Vererbung, Kette von Konstruktoren Kette von Konstruktoren: Ohne expliziten Aufruf wird am Anfang der Standardkonstruktor der Superklasse aufgerufen, d.h. der Konstruktor der Subklasse wird ergänzt um super(); Der Standardkonstruktor der Superklasse muss in diesem Fall existieren! Das bedeutet, dass jeder Konstruktor implizit oder explizit oder indirekt (via einen anderen Konstruktor der gleichen Klasse) mit dem Aufruf eines Konstruktors der Superklasse beginnt. Bei mehrstufiger Vererbung wird damit eine Kette von Konstruktoren aus allen Superklassen aufgerufen, bis schließlich zum Standardkonstruktor der Klasse Object
Konstruktoren und Vererbung, Beispiel Beispiel class Basis { i n t x ; Basis ( ) { / / Standardkonstruktor x = 5; class A b g e l e i t e t extends Basis { i n t y ; A b g e l e i t e t ( ) { / / Standardkonstruktor super ( ) ; / / Standardkonstruktor der y = 6; / / Superklasse public s t a t i c void main ( S t r i n g s ){ A b g e l e i t e t a = new A b g e l e i t e t ( ) ; System. out. p r i n t l n ( a. x ) ; / / e r g i b t 5 System. out. p r i n t l n ( a. y ) ; / / e r g i b t 6 27 / 41
Konstruktoren und Vererbung, Beispiel 28 / 41 Beispiel Ablauf der Instanziierung: class Vater { i n t x = 1; class Sohn extends Vater { i n t y = 2;... Sohn s = new Sohn ( ) ;
29 / 41 Konstruktoren und Vererbung (1) Die Referenz wird angelegt und mit null initialisiert. (2) Es wird Speicher für zwei Werte vom Typ int auf dem Heap (Freispeicher) beschafft. (3) Den Komponenten x und y werden die Werte 1 bzw. 2 zugewiesen, und es werden ggfs. weitere Initialisiererblöcke ausgeführt. (4) Der Konstruktor (hier: Standardkonstruktor) der Klasse Sohn wird aufgerufen. Dieser ruft als erstes den Standardkonstruktor der Basisklasse Vater und der wiederum den Standardkonstruktor der Klasse Object auf. (5) Die Variable s erhält eine Referenz auf das neu erzeugte Objekt.
Gliederung 30 / 41 1 Überblick: Vererbung 2 Grundidee Vererbung 3 Verdeckte Variablen 4 Verdeckte Methoden 5 Konstruktoren und Vererbung 6 Klassen und final 7 Zugriffsrechte und Vererbung 8 Abstrakte Methoden und Klassen
Klassen und final 31 / 41 Die Angabe von final ist bei Klassen, Methoden und Instanzen möglich. Dies ist bei Klassen und Methoden sinnvoll, die nicht weiter spezialisiert werden können. Es erhöht die Effizienz, da eine frühe Bindung erfolgen kann. Das bedeutet, dass Methoden eventuell auch inline erzeugt werden (kein Aufruf, keine Parameterübergabe usw.). Desweiteren bietet es einen Schutz vor trojanischen Pferden, die die Funktionalität der Klasse ersetzen könnten. (1) Klassen mit dem Wortsymbol final dürfen nicht vererbt werden. (2) Methoden mit dem Wortsymbol final dürfen nicht vererbt werden, d.h. bei einer Methode mit gleicher Signatur in der abgeleiteten Klasse tritt ein Fehler auf, dagegen ist eine Methode mit einer anderen Signatur erlaubt. (3) Instanzen mit dem Wortsymbol final sind konstant und dürfen folglich nicht verändert werden.
32 / 41 Klassen und final Achtung Die Komponenten der Instanz sind damit allerdings nicht automatisch konstant!
Klassen und final 33 / 41 Beispiel class Punkt { i n t x, y ; f i n a l void verschiebe ( i n t dx, i n t dy ) { x += dx ; y += dy ; class FarbPunkt extends Punkt { Color c ; void verschiebe ( Punkt p ) { / / ok! x += p. x ; y += p. y ; / / andere Signatur void verschiebe ( i n t dx, i n t dy ) { / / Fehler! x += dx ; y += dy ; / / g l e i c h e Signatur public s t a t i c void main ( String s ){ f i n a l Punkt p = new Punkt ( ) ; p = new Punkt ( ) ; / / Fehler! p = null ; / / Fehler! p. x = 7; / / e r l a u b t!
Gliederung 34 / 41 1 Überblick: Vererbung 2 Grundidee Vererbung 3 Verdeckte Variablen 4 Verdeckte Methoden 5 Konstruktoren und Vererbung 6 Klassen und final 7 Zugriffsrechte und Vererbung 8 Abstrakte Methoden und Klassen
35 / 41 Zugriffsrechte und Vererbung Die Zugriffsrechte von Methoden dürfen beim Überschreiben in der abgeleiteten Klasse nicht reduziert werden. Die Reihenfolge lautet dabei: private default protected public Achtung Die Umkehrung der Reihenfolge ist verboten, da aufgrund der Polymorphie ein Objekt der Basisklasse in Wirklichkeit zur abgeleiteten Klasse gehören kann! In diesem Fall müssen polymorphe Methoden zugreifbar bleiben! Bei Variablen und überladenen Methoden existiert diese Einschränkung nicht!
Zugriffsrechte und Vererbung, Beispiel 36 / 41 Beispiel class Mutter { private void a ( ) {... void b ( ) {... protected void c ( ) {... public void d ( ) {... class Tochter extends Mutter { / / Ueberschreiben von Methoden der Superklasse Mutter
37 / 41 Zugriffsrechte und Vererbung Folgende Varianten sind beim Überschreiben der Methoden aus der Superklasse Mutter möglich: a(): kein Überschreiben möglich, allerdings ist eine Neudefinition mit beliebigen Rechten möglich. b(): Überschreiben mit default, protected oder public möglich. c(): Überschreiben mit protected oder public möglich. d(): Überschreiben mit public möglich.
Gliederung 38 / 41 1 Überblick: Vererbung 2 Grundidee Vererbung 3 Verdeckte Variablen 4 Verdeckte Methoden 5 Konstruktoren und Vererbung 6 Klassen und final 7 Zugriffsrechte und Vererbung 8 Abstrakte Methoden und Klassen
39 / 41 Abstrakte Methoden und Klassen Syntax abstract class Klassenname { abstract M o d i f i z i e r e r Ergebnistyp Methodenname (... ) ; Achtung Abstrakte Methoden dürfen keinen Rumpf besitzen! Ist eine Methode einer Klasse abstrakt, so muss auch die Klasse selber abstrakt sein. Von abstrakten Klassen dürfen keine Instanzen gebildet werden. Die Klassen dienen nur zur Vorlage bei der Vererbung. Die abgeleitete Klasse kann abstrakt sein, muss aber nicht, falls alle abstrakten Methoden durch konkrete Implementierungen überschrieben werden.
Abstrakte Methoden und Klassen: Beispiel 40 / 41 Beispiel Vertrag KaufVertrag VersicherungsVertrag Die Klasse Vertrag ist abstrakt, es können keine Instanzen gebildet werden. Sie dient nur als Grundlage zur Formulierung der abgeleiteten Klassen KaufVertrag und VersicherungsVertrag. Eine abstrakte Klasse kann auch als Protokollklasse aufgefasst werden, die nur die Methoden zu ihrer Verwendung definiert, aber keine Implementierung enthält.
41 / 41 Abstrakte Klassen: Alternative Konzepte Ähnlich zu abstrakten Klassen verhalten sich die beiden folgenden Sprachelemente: Sind alle Konstruktoren einer Klasse private, so können nur innerhalb der Klasse Instanzen gebildet werden. Ansonsten ist der Aufruf der Konstruktoren verboten, es können also keine weiteren Instanzen gebildet werden. Schnittstellen (Interfaces) sind eine Sammlung von Konstanten und abstrakten Methoden, die eine bestimmte Funktionalität beschreiben aber nicht implementieren. Dies wird in einem eigenen Kapitel beschrieben.