Lernpfad:Objektorientierte Programmierung mit Java/Vererbung: Unterschied zwischen den Versionen
Jneug (Diskussion | Beiträge) |
Jneug (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
Zeile 1: | Zeile 1: | ||
{{Navigation}} | {{Navigation}} | ||
''Vererbung'' ist eines der wichtigsten Konzepte der Objektorientierten Programmierung. Mit ihr ist es möglich komplexe Problembereiche in sinnvolle Klassenhierarchien zu unterteilen. Dabei werden Eigenschaften und Fähigkeiten, die mehrere Klassen besitzen, nur einmal in einer ''Oberklasse'' implementiert und an eine oder mehrere ''Unterklassen'' weiter''vererbt''. | ''Vererbung'' ist eines der wichtigsten Konzepte der Objektorientierten Programmierung. Mit ihr ist es möglich komplexe Problembereiche in sinnvolle Klassenhierarchien zu unterteilen. Dabei werden Eigenschaften und Fähigkeiten, die mehrere Klassen besitzen, nur einmal in einer '''Oberklasse''' implementiert und an eine oder mehrere '''Unterklassen''' weiter ''vererbt''. | ||
== Vererbung im Überblick == | == Vererbung im Überblick == | ||
Zeile 12: | Zeile 12: | ||
[[Datei:UML Vererbung 1.jpg|center]] | [[Datei:UML Vererbung 1.jpg|center]] | ||
Es ergeben sich einige Dopplungen bei Eigenschaften und Methoden. Jede Klasse besitzt x- und y-Koordinaten und eine Richtung als Attribut, sowie die Methoden | Es ergeben sich einige Dopplungen bei Eigenschaften und Methoden. Jede Klasse besitzt x- und y-Koordinaten und eine Richtung als Attribut, sowie die Methoden <code>versetzen</code> und <code>drehen</code>. Diese müssten bei der Implementierung jeweils exakt gleich umgesetzt werden, was neben viel Aufwand sehr fehleranfällig ist. | ||
Statt dessen können im Problembereich logische Zusammenhänge zwischen den Klassen identifiziert werden. Jede Klasse ''ist eine'' "''Form''". Ein "''Quadrat''" ''ist ein'' "''Rechteck''". Die konkreten Form-Klassen haben alle bestimmte Attribute und Methoden gemeinsam. | Statt dessen können im Problembereich logische Zusammenhänge zwischen den Klassen identifiziert werden. Jede Klasse ''ist eine'' "''Form''". Ein "'''Quadrat'''" ''ist ein'' "''Rechteck''". Die konkreten Form-Klassen haben alle bestimmte Attribute und Methoden gemeinsam. | ||
<code>Form</code> ist also eine '''Oberklasse'' von <code>Dreieck</code> und <code>Rechteck</code>. <code>Quadrat</code> ist eine '''Unterklasse''' von <code>Rechteck</code>. (Also ist <code>Rechteck</code> wiederum '''Oberklasse''' von <code>Quadrat</code>.) Die Methoden müssen so nur einmal in <code>Form</code> implementiert werden, sind aber durch die Vererbung in allen Objektinstanzen verfügbar. | |||
Das neue Implementierungsdiagramm sieht so aus: | Das neue Implementierungsdiagramm sieht so aus: | ||
Zeile 26: | Zeile 26: | ||
== Methoden überschreiben == | == Methoden überschreiben == | ||
Beim Überschreiben bekommen abgeleitete Klassen eine | Beim Überschreiben bekommen abgeleitete Klassen eine eigeneTitle: | ||
Tags: | |||
Format: standard | |||
Image: Version mindestens einer Methode der Basisklasse. | |||
Betrachte das folgende Klassendiagramm mit einer Ober- und drei erbenden Unterklassen und die dazugehörige Implementierung. | Betrachte das folgende Klassendiagramm mit einer Ober- und drei erbenden Unterklassen und die dazugehörige Implementierung. |
Version vom 9. Oktober 2018, 21:12 Uhr
Vererbung ist eines der wichtigsten Konzepte der Objektorientierten Programmierung. Mit ihr ist es möglich komplexe Problembereiche in sinnvolle Klassenhierarchien zu unterteilen. Dabei werden Eigenschaften und Fähigkeiten, die mehrere Klassen besitzen, nur einmal in einer Oberklasse implementiert und an eine oder mehrere Unterklassen weiter vererbt.
Vererbung im Überblick
Ober- und Unterklassen
Am besten verdeutlicht dies ein Beispiel: Nehmen wir an, es soll ein geometrisches Zeichenprogramm nach folgender Beschreibung umgesetzt werden.
Es gibt verschiedene Formen wie Rechteck, Dreieck und Quadrat. Jede Form besitzt eine x- und y-Koordinate und eine Richtung. Formen können versetzt und gedreht werden. Rechtecke besitzen zwei Seitenlängen. Bei Quadraten sind beide Seitenlängen gleich. Dreiecke werden über zwei Punkte festgelegt, die auch eine x- und y-Koordinate besitzen. Die dritte Ecke wird durch die Position des Dreiecks festgelegt.
Ein erstes Implementierungsdiagramm ohne Vererbung könnte so aussehen:
Es ergeben sich einige Dopplungen bei Eigenschaften und Methoden. Jede Klasse besitzt x- und y-Koordinaten und eine Richtung als Attribut, sowie die Methoden versetzen
und drehen
. Diese müssten bei der Implementierung jeweils exakt gleich umgesetzt werden, was neben viel Aufwand sehr fehleranfällig ist.
Statt dessen können im Problembereich logische Zusammenhänge zwischen den Klassen identifiziert werden. Jede Klasse ist eine "Form". Ein "Quadrat" ist ein "Rechteck". Die konkreten Form-Klassen haben alle bestimmte Attribute und Methoden gemeinsam.
Form
ist also eine Oberklasse von Dreieck
und Rechteck
. Quadrat
ist eine Unterklasse' von Rechteck
. (Also ist Rechteck
wiederum Oberklasse von Quadrat
.) Die Methoden müssen so nur einmal in Form
implementiert werden, sind aber durch die Vererbung in allen Objektinstanzen verfügbar.
Das neue Implementierungsdiagramm sieht so aus:
- Folgende Begriffe sollen in Form eines Klassendiagramms in eine Klassenhierarchie umgesetzt werden: Gebäude - Kirche - Einfamilenhaus - Hochhaus - Haus - Bungalow - Dom - Kathedrale.
Von jedem Gebäude soll die Höhe und die zugelassene Anzahl Bewohner bzw. Besucher abrufbar sein. Die Höhe von Häusern berechnet sich aus der Anzahl der Stockwerke und der Höhe pro Stockwerk. In einem Hochaus sind pro Stockwerk eine Anzahl Personen zugelassen.
Wähle zu diesem Zweck geeignete Attribute für die einzelnen Klassen. Beachte dabei, welche Attribute von der bzw. den Oberklasse(n) geerbt werden. - Implementiere die Klassen. Nutz dazu das Vererbungskonzept so weit es geht aus.
Methoden überschreiben
Beim Überschreiben bekommen abgeleitete Klassen eine eigeneTitle: Tags: Format: standard Image: Version mindestens einer Methode der Basisklasse.
Betrachte das folgende Klassendiagramm mit einer Ober- und drei erbenden Unterklassen und die dazugehörige Implementierung.
class Tier {
public void sagWas() {
System.out.println("- Stille -");
}
}
class Biene extends Tier {
public void sagWas() {
System.out.println("Summ, Summ, Summ!");
}
}
class Frosch extends Tier {
public void sagWas() {
System.out.println("Quak! Quak!");
}
}
class Unbekannt extends Tier {
}
public class Zoo {
public static void main(String[] args) {
Tier t = new Tier();
Frosch f = new Frosch();
Biene b = new Biene();
System.out.print( "Ein Tier sagt " ); t.sagWas();
System.out.print( "Ein Frosch sagt " ); f.sagWas();
System.out.print( "Eine Biene sagt " ); b.sagWas();
Tier werBinIch = new Unbekannt();
// Was sage ich?
werBinIch.sagWas();
}
}
Die Unterklassen Biene
und Frosch
implementieren die Methode sagWas() : int
, die auch in der Oberklasse Tier
vorhanden sind. Sie überschreiben die Methode in der Oberklasse und können so ihre Funktion (in diesem Beispiel die Ausgabe) verändern.
- Lies den "Abschnitt 6.4.1: Methoden in Unterklassen mit neuem Verhalten ausstatten" im Onlinebuch "Java ist auch eine Insel" bis zur Überschrift "Die Annotation @Override".
- Erstellt ein kleines Beispielprojekt, an dem das Konzept "Überschreiben" erklärt werden kann.
Quiz
Welche Ausgabe wird vom Quelltext oben erzeugt?
Ein Tier sagt - Stille -
Ein Frosch sagt Quak, Quak!
Eine Biene sagt Summ, Summ, Summ!
Was sage ich? - Stille -()
super
und this
Wird eine Methode von einer Unterklasse überschrieben möchte man dennoch manchmal explizit die überschriebene Methode der Oberklasse aufrufen. Für diese Fälle gibt es das bekannte Schlüsselwort super
. Es bezieht sich immer auf die Oberklasse der aktuellen Klasse. Um explizit die aktuelle Klasse zu referenzieren, kann das Schlüsselwort this
benutzt werden.
class Tier {
// Das Attribut ist private und von der Unterklasse nicht nutzbar.
private String name;
public Tier( String pName ) {
this.name = pName;
}
public void ausgabe() {
System.out.println( "Mein Name ist " + this.name );
}
}
class Hund extends Tier {
private String rasse;
public Hund( String pName, String pRasse ) {
super(pName);
this.rasse = pRasse;
}
// Will die Ausgabe auch den Namen ausgeben (der in der Oberklasse als private markiert ist),
// muss die Methode "ausgabe()" der Oberklasse explizit aufgerufen werden.
public void ausgabe() {
System.out.println( "Ich bin ein " + this.rasse );
super.ausgabe();
}
}
Das Schlüsselwort final
Möchte man verhindern, dass eine Unterklasse eine Methode überschreibt, dann kann man sie als final
deklarieren.
class Tier {
// Das Attribut ist private und von der Unterklasse nicht nutzbar.
private String name;
public Tier( String pName ) {
this.name = pName;
}
public final void ausgabe() {
System.out.println( "Mein Name ist " + this.name );
}
}
class Hund extends Tier {
private String rasse;
public Hund( String pName, String pRasse ) {
super(pName);
this.rasse = pRasse;
}
// Fehler
public void ausgabe() {
System.out.println( "Ich bin ein " + this.rasse );
super.ausgabe();
}
}