5.6 Vererbung • Klassen können zueinander in einer "ist ein"- Beziehung stehen • Beispiel: Jeder PKW ist ein Kraftfahrzeug, jedes Kraftfahrzeug ist ein Transportmittel aber: auch jeder LKW ist ein Kraftfahrzeug und jeder Zug, jedes Schiff und jedes Flugzeug ist ein Transportmittel Informatik I – Java © Klaus Hinrichs 5-145 Vererbung Transportmittel Kraftfahrzeug PKW LKW SLK 230 A 170 © Klaus Hinrichs Zug Schiff Flugzeug Multi-Eng. A 340 Informatik I – Java B 737 Single-Eng. C 172 Traveler 5-146 Vererbung • Sowohl PKWs als auch LKWs besitzen Fahrersitze und Fahrertüren, es handelt sich also um Attribute der Oberklasse Kraftfahrzeug • Sowohl PKWs als auch LKWs haben die Methoden Sitz verstellen,Tür schließen und fahren, es sind Methoden der Oberklasse Kraftfahrzeug • PKWs haben jedoch mit der Rückbank und dem Kofferraum eigene Attribute und mit hinten einsteigen eigene Methoden • LKWs haben mit der Ladefläche und dem Anhänger auch eigene Attribute und beladen ist eine eigene Methode ! Unterklassen PKW und LKW besitzen alle Attribute und Methoden der Oberklasse Kraftfahrzeug, haben jedoch noch zusätzliche © Klaus Hinrichs Informatik I – Java 5-147 Ähnlichkeiten bei Objekten • Zusammenfassen von gleichen Attributen und Methoden • Beispiel Konten: Girokonto kontostand: int inhaber: Person habenzinsen: int sollzinsen: int dispo: int holekontostand() zahle() © Klaus Hinrichs Sparkonto kontostand: int inhaber: Person habenzinsen: int holekontostand() zahle() kuendigen() Informatik I – Java Festgeldkonto kontostand: int inhaber: Person habenzinsen: int mindbetrag: int laufzeit: int holekontostand() zahle() kuendigen() 5-148 Vererbung • Erweiterung des Klassenmodells: Konto kontostand: int inhaber: Person habenzinsen: int holekontostand() zahle() Girokonto sollzinsen: int dispo: int © Klaus Hinrichs Sparkonto kuendigen() Festgeldkonto mindbetrag: int laufzeit: int kuendigen() Informatik I – Java 5-149 Vererbung • Die vererbende Klasse heißt Superklasse. • Die erbenden Klassen sind Unter- oder Subklassen. • Konto ist also die Superklasse der Klassen Girokonto, Festgeldkonto, Sparkonto. Diese sind die Subklassen der Klasse Konto. © Klaus Hinrichs Informatik I – Java 5-150 Verhältnis zwischen Objekten erbender Klassen • Alle Objekte sind Konten! • Einige sind besondere Arten von Konten. • Die Mengen der Sparkonten, Girokonten, Festgeldkonten sind jeweils eine Teilmenge der Menge der Konten. • Die Teilmengen sind disjunkt. Konto Sparkonto Girokonto Festgeldkonto © Klaus Hinrichs Informatik I – Java 5-151 Verhältnis zwischen Objekten erbender Klassen • Deklarationen: Girokonto einGirokonto; Sparkonto einSparkonto; Konto einKonto, einAnderesKonto; • Zulässige Zuweisungen: einGirokonto = new Girokonto(); einSparkonto = new Sparkonto(); einGirokonto.sollzinsen = 12; einKonto = einGirokonto; einAnderesKonto = new Sparkonto(); • Nicht erlaubte Zuweisungen: einSparKonto = einGirokonto; einGirokonto = new Sparkonto(); © Klaus Hinrichs Informatik I – Java 5-152 Verhältnis zwischen Objekten erbender Klassen • Jedes Sparkonto / Girokonto ist auch ein Konto, deshalb ist einKonto = einSparkonto; zulässig. Allerdings ist der Zugriff auf alle Attribute nicht möglich, einKonto kann nur auf die Konto-Attribute zugreifen. • Ein Objekt einer Klasse kann also mehrere Erscheinungsformen haben, es kann ein Objekt der Klasse selbst sein oder es kann ein Objekt einer der Unterklassen dieser Klasse sein. Man nennt es polymorph. © Klaus Hinrichs Informatik I – Java 5-153 Verhältnis zwischen Objekten erbender Klassen • Was passiert bei folgender Anweisung? if (x % 2 == 0) einKonto = einSparkonto; else einKonto = einGirokonto; Der Compiler ist nicht in der Lage, die Klasse von einKonto zu bestimmen. einKonto kann nach der if-else Anweisung eine von mehreren Klassen haben, es ist polymorph. • Ist folgende Anweisung erlaubt? einKonto = (x % 2 == 0 ? einGirokonto : einSparkonto); • Nein, da einGirokonto und einSparkonto nicht zuweisungskompatibel sind! © Klaus Hinrichs Informatik I – Java 5-154 Die Klasse Konto public class Konto { private int kontostand = 0; private Waehrungsrechner wr; private Person inhaber; private int habenzinsen; public Konto(Person inhaber, Waehrungsrechner wr) { this.inhaber = inhaber; this.wr = wr; } public void zahle(int pfennige) { int euroCent = wr.konvInEuroCent(pfennige); kontostand += euroCent; } public int holeKontostand() { int pfennige = wr.konvInPfennige(kontostand); return (pfennige); } } // Ende der Klasse Konto © Klaus Hinrichs Informatik I – Java 5-155 Die Klasse Girokonto public class Girokonto extends Konto { private int sollzinsen; private int dispo; public Girokonto(Person inhaber, Waehrungsrechner wr) { super(inhaber, wr); } … } // Ende der Klasse Girokonto © Klaus Hinrichs Informatik I – Java 5-156 Technische Aspekte der Vererbung • Vererbung wird über das Schüsselwort extends realisiert: class Unterklasse extends Oberklasse { ... // Hier zusätzliche Attribute ... // und Methoden } • Die neu definierte Unterklasse erweitert also die anderswo definierte Oberklasse um neue Attribute und Methoden. • Alle Methoden und Attribute der Oberklasse werden übernommen. • Jede Klasse hat genau eine Oberklasse (Java kennt keine Mehrfachvererbung). • Ist keine Oberklasse definiert (kein extends), so ist die Systemklasse Object die Oberklasse " Object ist eine Oberklasse für alle Klassen (bis auf Object selbst) • Konstruktoren werden nicht vererbt, Konstruktoren der abgeleiteten Klasse müssen neu definiert werden! © Klaus Hinrichs Informatik I – Java 5-157 Technische Aspekte der Vererbung • Über das Schlüsselwort super kann am Anfang eines Konstruktors der abgeleiteten Klasse ein Konstruktor der Oberklasse aufgerufen werden. • Beispiel: class A { A(String name) { ... } } class B extends A { B(String name, int a) { super(name); // Aufruf des Oberklassenkonstr. } } • Wenn in der ersten Anweisung des Subklassen-Konstruktors nicht einer der Konstruktoren der Superklasse aufgerufen wird, dann wird der parameterlose Superklassen-Konstruktor (Standard-Konstruktor) automatisch aufgerufen, bevor irgendeine andere Anweisung des Subklassen-Konstruktors aufgerufen wird. © Klaus Hinrichs Informatik I – Java 5-158 Zugriffsrechte für Attribute und Methoden • private Methoden und Attribute sind nur in der Klasse zugreifbar, in der sie definiert sind. • protected Methoden und Attribute sind in der Klasse selbst, von allen Unterklassen und von allen Klassen im gleichen package zugreifbar. • Methoden und Attribute ohne Zugriffs-modifikator sind in der Klasse und von allen Klassen im gleichen package zugreifbar. • public Methoden und Attribute sind von allen Klassen aus zugreifbar. © Klaus Hinrichs Informatik I – Java 5-159 Überschreiben von Methoden • Methode berechneZinsen(int tage) hat gleiche Implementierung in Sparkonto und Festgeldkonto, aber: in Girokonto Berechnung aus Sollzinsen und Habenzinsen. Lösung: Standard-Implementierung in Konto und Überschreiben in Girokonto public class Konto { ... protected int berechneZinsen(int tage) { ... } ... } public class Girokonto extends Konto { ... protected int berechneZinsen(int tage) { ... } ... } © Klaus Hinrichs Informatik I – Java 5-160 Zugriff auf überschriebene Attribute / Methoden • In einem Objekt einer abgeleiteten Klasse ist super eine Referenz auf das Teilobjekt der Oberklasse, Attribute und Methoden der Oberklasse lassen sich über super ansprechen (auch überschriebene Attribute und Methoden). • Beispiel: class A { int variable; void methode() { ... } } class B extends A { int variable; // Überschreibendes Attr. void methode() { ... } // Überschreibende Meth. void methode2() { super.variable = 3; // Zugriff auf überschriebene super.methode(); // Attr. und Meth. der Oberklasse } } © Klaus Hinrichs Informatik I – Java 5-161 Schlüsselwort: final • final verhindert, daß eine Methode überschrieben wird: public final int holeKontostand() { ... } • final verhindert, daß Unterklassen von einer Klasse abgeleitet werden können: public final class Girokonto extends Konto { ... } Von Girokonto können keine weiteren Unterklassen durch Vererbung abgeleitet werden. Alle Methoden einer finalen Klasse sind implizit auch final. • Finale Klassen und Methoden sind manchmal aus Sicherheitsgründen erforderlich. Sie tun das, was sie tun sollen, und sie können nicht durch Überschreiben manipuliert werden. Typische Anwendung: eine Methode zur Passwort-Prüfung. • final-Variablen können nach ihrer Initialisierung nicht mehr verändert werden, sie sind also Konstanten: public final int mwst; © Klaus Hinrichs Informatik I – Java 5-162 Abstrakte Methoden / Klassen • Problem: Jede Subklasse hat die gleiche Methode, aber unterschiedliche Implementierung. • Beispiel: public int auszahlen(int betrag); – Girokonto: beliebige Auszahlung bis Limit – Sparkonto: Restguthaben von DM 5,- nötig (außer nach Kündigung) – Festgeld: Auszahlung erst nach Ende der Laufzeit • Lösung: abstrakte Methode in der Superklasse. Eine abstrakte Methode ist eine Methode, für die nur eine Signatur (Kopf der Methode), aber keine Implementierung (kein Rumpf) existiert. • Enthält eine Klasse eine abstrakte Methode, so ist die Klasse selbst abstrakt. Es können keine Objekte zu einer abstrakten Klasse erzeugt werden. • Eine Unterklasse muß die abstrakten Methoden der Oberklasse implementieren, oder sie ist selbst wieder abstrakt. © Klaus Hinrichs Informatik I – Java 5-163 Beispiel … public class Datum { public Datum(int tag, int monat, int jahr) { ...} public void setzeDatum(int tag, int monat, int jahr) { ... } public static Datum aktuellesDatum() { ... } public boolean istSpaeterAls(Datum dat) { ...} public boolean istAbgelaufen() { ...} public boolean istGleich(Datum dat) { ...} public int gibDifferenz(Datum dat) { ...} } © Klaus Hinrichs Informatik I – Java 5-164 … Beispiel … public abstract class Konto { protected Datum letzteTransaktion; ... public void einzahlen(int betrag) { Datum heute = Datum.aktuellesDatum(); int zinstage = heute.gibDifferenz(letzteTransaktion); int zinsen = berechneZinsen(zinstage); zahle(betrag + zinsen); } public abstract int auszahlen(int betrag); } • Schlüsselwort abstract vor Methode und Klasse! © Klaus Hinrichs Informatik I – Java 5-165 … Beispiel class Girokonto extends Konto { ... public int auszahlen(int betrag) { Datum heute = Datum.aktuellesDatum(); int zinstage = heute.gibDifferenz(letzteTransaktion); int zinsen = berechneZinsen(zinstage); zahle(zinsen); if (kontostand - betrag > dispo) { zahle(-betrag); return (betrag); } else System.out.println("Keine Auszahlung möglich"); return (0); } } © Klaus Hinrichs Informatik I – Java 5-166 Polymorphie • Wunsch: Alle Objekte aus der Oberklasse Konto sollen in der gleichen Weise behandelt werden können. • Lösung: Eine Oberklassen-Referenz kann auch auf Objekte der Subklassen verweisen. Methoden der Oberklasse können so aufgerufen werden. Wurde eine Methode von einer Subklasse überschrieben, so wird nicht die Methodenimplementierung der Oberklasse aufgerufen, sondern die Implementierung der Subklasse. © Klaus Hinrichs Informatik I – Java 5-167 Polymorphie • Methoden können so mit allen möglichen Konten arbeiten: public int berechneVermoegen(Konto[] konten) { int vermoegen = 0; for (int i = 0; i < konten.length; i++) { Konto k = konten[i]; vermoegen += k.holeKontostand(); } return (vermoegen); } • Methodenaufruf wird an die entsprechende Subklasse weitergeleitet © Klaus Hinrichs Informatik I – Java 5-168 Technische Aspekte der Polymorphie • Polymorphie wird bei Vererbung durch Überschreiben der Methoden der Oberklasse erreicht, dabei muß die Signatur (also Parameterliste und Rückgabetyp) mit der Methode der Oberklasse übereinstimmen. • Beim Überschreiben werden die allgemeineren Methoden (der Oberklasse) durch die konkreteren der Unterklasse überschrieben. • Auch wenn ein Objekt durch eine Variable eines allgemeineren Typs referenziert wird, so werden immer die zum Objekt gehörenden Methoden aufgerufen. • Überschreiben darf nicht mit Überladen verwechselt werden, bei überladenen Methoden hat man unterschiedliche Signaturen und nur der Methodenname ist der gleiche. © Klaus Hinrichs Informatik I – Java 5-169 instanceof • Da jedes Objekt auch über Referenzen der Oberklasse angesprochen werden kann, ist nicht immer klar, zu welcher Klasse ein Objekt gehört. Daher gibt es das Schlüsselwort instanceof , um die Klassenzugehörigkeit eines Objektes zu bestimmen: if(Objektname instanceof Klassenname) Anweisung; • Die Abfrage liefert auch dann true, wenn durch Klassenname eine Oberklasse für das zu Objektname zugehörige Objekt angegeben wird. © Klaus Hinrichs Informatik I – Java 5-170 Beispiel: Klasse X public abstract class X { private int a; public X() { this.a = 0; } public X(int a) { if (a >= 0) this.a = a; else this.a = 0; } protected void set(int a) { if (a >= 0) this.a = a; else this.a = 0; } protected int geta() { return a; } public abstract void print(); } © Klaus Hinrichs Informatik I – Java 5-171 Beispiel: Klasse Y public class Y extends X { private int b; public Y(int a, int b) { super(a); this.b = b; } public Y() { this(0, 0); } public void set(int a, int b) { set(a); this.b = b; } protected int getb() { return b; } public void print() { System.out.println("In Y: a = " + geta() + " b = " + b); } } © Klaus Hinrichs Informatik I – Java 5-172 Beispiel: Klasse Z public final class Z extends Y { private int c; public Z(int a, int b, int c) { super(a, b); this.c = c; } public Z() { this(0, 0, 0); } public void set(int a, int b, int c) { super.set(a, b); this.c = c; } public void print() { System.out.println("In Z: a = " + geta() + " b = " + getb() + " c = " + c); } } © Klaus Hinrichs Informatik I – Java 5-173 Beispiel: Klasse Test public class Test { public static void main(String args[]) { System.out.println("Beginn Test"); Y y = new Y(1, 1); Z z = new Z(2, 2, 2); X x; y.print(); // In Y: a = 1 b = 1 z.print(); // In Z: a = 2 b = 2 c = 2 x = y; // x.set(3, 3); ist nicht erlaubt! x.set(3); x.print(); // In Y: a = 3 b = 1 x = z; // x.set(3, 3); ist nicht erlaubt! // x.set(3, 3, 3); ist nicht erlaubt! x.print(); // In Z: a = 2 b = 2 c = 2 Y y1 = z; // y1.set(4, 4, 4); ist nicht erlaubt! y1.set(5, 5); y1.print(); // In Z: a = 5 b = 5 c = 2 System.out.println("Ende"); } } © Klaus Hinrichs Informatik I – Java 5-174