Vererbung: Unterschied zwischen den Versionen
(22 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
[[Kategorie:Informatik]] [[Kategorie:Informatik-Abitur]] | |||
=Erklärvideo= | |||
* [https://youtu.be/CKab9DVPFto Vererbung, um eine bestehende Klasse zu erweitern: Beispiel ''AnzahlQueue''] | |||
* [https://youtu.be/OhZqyzWyDZg Vererbung und Polymorphie am Beispiel Buch - Fachbuch - Hörbuch (youtube)] | |||
=Fachbegriffe= | |||
s.Allgemeines, insbesondere die unterstrichenen Begriffe.<br/> | |||
Außerdem: öffentliche Methode, öffentliches Attribut | |||
=Allgemeines= | =Allgemeines= | ||
* Die '''vererbende''' Klasse wird meist '''<u>Superklasse</u>, Basisklasse oder Oberklasse | ''Der folgende Text ist aus [https://de.wikipedia.org/wiki/Vererbung_(Programmierung) Wikipedia] und gekürzt.'' | ||
* Die '''erbende''' Klasse wird '''<u>Subklasse</u>, abgeleitete Klasse oder Unterklasse | |||
* Den Vorgang | '''Vererbung''' dient dazu, aufbauend auf existierenden Klassen neue zu schaffen. Eine neue Klasse kann dabei eine Erweiterung oder eine Einschränkung der ursprünglichen Klasse sein. | ||
* In UML wird eine Vererbungsbeziehung durch einen '''Pfeil mit einer dreieckigen (leeren!) Spitze''' dargestellt, der von der | |||
* Die '''vererbende''' Klasse wird meist '''<u>Superklasse</u>, Basisklasse oder Oberklasse''' genannt. | |||
* Die '''erbende''' Klasse wird '''<u>Subklasse</u>, abgeleitete Klasse oder Unterklasse''' genannt. | |||
* Den Vorgang nennt man '''Vererbung''', weil die Subklasse alle öffentlichen Attribute und Methoden der Superklasse "erbt". | |||
* In UML wird eine Vererbungsbeziehung durch einen '''Pfeil mit einer dreieckigen (<u>leeren</u>!) Spitze''' dargestellt, der von der Subklasse zur Superklasse zeigt. | |||
* Der Subklasse stehen alle <code>public</code>-Methoden und <code>public</code>-Attribute der Superklasse zur Verfügung. | * Der Subklasse stehen alle <code>public</code>-Methoden und <code>public</code>-Attribute der Superklasse zur Verfügung. | ||
* Geerbte Attribute und Methoden werden in der Darstellung der Subklasse nicht wiederholt. Das gilt sowohl für das UML-Diagramm als auch für den Java-Quelltext. | * Geerbte Attribute und Methoden werden in der Darstellung der Subklasse nicht wiederholt. Das gilt sowohl für das UML-Diagramm als auch für den Java-Quelltext. | ||
* Abgeleitete Klasse und Basisklasse stehen typischerweise in einer '''"ist-ein"-Beziehung''' zueinander. | * Abgeleitete Klasse und Basisklasse stehen typischerweise in einer '''<u>"ist-ein"</u>-Beziehung''' zueinander. | ||
=Beispiel= | =Beispiel 1: Buch - Fachbuch - Hörbuch= | ||
[[File:Klassendiagramm-Buch-Fachbuch-Hoerbuch.png|thumb|Klassendiagramm |717px]] | [[File:Klassendiagramm-Buch-Fachbuch-Hoerbuch.png|thumb|Klassendiagramm |717px]] | ||
* <code>Fachbuch</code> | * <code>Fachbuch</code> '''"ist-ein"''' <code>Buch</code>. <code>Hoerbuch</code> auch. | ||
* <code>Buch</code> ist die '''Superklasse''' | * <code>Buch</code> ist die '''Superklasse''' | ||
* <code>Fachbuch</code> und <code>Hoerbuch</code> sind die '''Subklassen'''. | * <code>Fachbuch</code> und <code>Hoerbuch</code> sind die '''Subklassen'''. | ||
* <code>Fachbuch</code> und <code>Hoerbuch</code> '''erben''' von <code>Buch</code>. | |||
* <code>Fachbuch</code> und <code>Hoerbuch</code> verfügen über alle <code>public</code>-Methoden von Buch. | * <code>Fachbuch</code> und <code>Hoerbuch</code> verfügen über alle <code>public</code>-Methoden von Buch. | ||
==Implementierung== | ==Implementierung== | ||
<code> | <code> | ||
'''public class Buch'''{ | '''public class Buch'''{ | ||
private String titel; | private String titel; | ||
Zeile 46: | Zeile 62: | ||
} | } | ||
} | } | ||
'''public class Fachbuch <u>extends Buch</u>'''{ | '''public class Fachbuch <u>extends Buch</u>'''{ | ||
private String kategorie; | private String kategorie; | ||
Zeile 70: | Zeile 86: | ||
} | } | ||
} | } | ||
public class Hoerbuch <u>extends Buch</u>{ | '''public class Hoerbuch <u>extends Buch</u>'''{ | ||
private double dauer; | private double dauer; | ||
private String sprecher; | private String sprecher; | ||
Zeile 100: | Zeile 116: | ||
} | } | ||
} | } | ||
</code> | </code> | ||
'''Erläuterungen:''' | '''Erläuterungen:''' | ||
Zeile 107: | Zeile 123: | ||
* Im Konstruktor der Subklassen muss zuerst mit dem Schlüsselwort <u><code>super(...)</code></u> der Konstruktor der Superklasse aufgerufen werden. | * Im Konstruktor der Subklassen muss zuerst mit dem Schlüsselwort <u><code>super(...)</code></u> der Konstruktor der Superklasse aufgerufen werden. | ||
** D.h. zum Beispiel für <code>Fachbuch</code>: Um ein Objekt vom Typ <code>Fachbuch</code> zu erzeugen, muss erst der Konstruktor von <code>Buch</code> aufgerufen werden; das ist auch inhaltlich wichtig, denn nur so können <code>titel</code> und <code>autor</code> richtig eingetragen werden. | ** D.h. zum Beispiel für <code>Fachbuch</code>: Um ein Objekt vom Typ <code>Fachbuch</code> zu erzeugen, muss erst der Konstruktor von <code>Buch</code> aufgerufen werden; das ist auch inhaltlich wichtig, denn nur so können <code>titel</code> und <code>autor</code> richtig eingetragen werden. | ||
* Mit <code><u>super.info()</u></code> greifen die Subklassen auf die Methode <code>info()</code> der Superklasse zu. | * Mit <code><u>super.info()</u></code> greifen die Subklassen auf die Methode <code>info()</code> der Superklasse zu. | ||
* Dass die Methode <code>info()</code> in der Superklasse und in den Subklassen vorkommt, liegt an der '''[[Polymorphie]]'''. | |||
=Beispiel 2: StackMitAnzahl= | |||
Die Klasse <code>StackMitAnzahl</code> soll genauso funktionieren wie ein <code>Stack</code>. | |||
Zusätzlich wird im <code>StackMitAnzahl</code> die Anzahl der Elemente in einem Attribut <code>anzahl</code> gespeichert. | |||
==Strategie== | |||
Damit <code>StackMitAnzahl</code> das Attribut <code>anzahl</code> immer richtig aktualisiert, müssen alle Methoden neu programmiert werden, die die Anzahl verändern, d.h. die Methoden <code>push</code> und <code>pop</code>. | |||
(Bei <code>isEmpty</code> und <code>top</code> verändert sich die Anzahl nicht.) | |||
==Implementierung== | |||
<code> | |||
public class StackMitAnzahl<ContentType> '''extends Stack<ContentType>'''{ | |||
private int anzahl; | |||
// Konstruktor ist nicht unbedingt notwendig | |||
public StackMitAnzahl(){ | |||
'''super()'''; | |||
} | |||
public void push(ContentType pContent){ | |||
if(pContent == null){ return;} | |||
'''super.push(pContent)'''; | |||
anzahl++; | |||
} | |||
public void pop(){ | |||
if(isEmpty()) { return;} | |||
'''super.pop()'''; | |||
anzahl--; | |||
} | |||
// Methode, um die Anzahl auszulesen | |||
public int getAnzahl(){ | |||
return anzahl; | |||
} | |||
} | |||
</code> | |||
<u>Hinweise:</u> | |||
* Die Abbruchbedingung bei <code>push</code> ist notwendig, weil die push-Methode von Stack für pContent == null den Stack nicht verändern würde - aber anzahl würde trotzdem eins hochgezählt! | |||
* Die Abbruchbedingung bei <code>pop</code> ist notwendig, weil die pop-Methode von Stack bei einem leeren Stack nichts tut - aber anzahl würde eins verringert! D.h. man hätte eine negative Anzahl. | |||
=Vererbung vs. Hat-Beziehung= | =Vererbung vs. Hat-Beziehung= | ||
In manchen Fällen darf man Vererbung nicht verwenden, obwohl es sich um eine "ist-ein"-Beziehung handelt. | In manchen Fällen darf man Vererbung nicht verwenden, obwohl es sich um eine "ist-ein"-Beziehung handelt. | ||
Im Hinblick auf das Zentralabitur ist vor allem das folgende Kriterium wichtig: | Im Hinblick auf das Zentralabitur ist vor allem das folgende Kriterium wichtig: | ||
* Können Methoden der Superklasse die Struktur der Subklasse zerstören? | * '''Können Methoden der Superklasse die Struktur der Subklasse zerstören?''' | ||
In diesen Fällen ist eine Modellierung mit einer Hat-Beziehung vorzuziehen. | In diesen Fällen ist eine Modellierung mit einer Hat-Beziehung vorzuziehen. | ||
== | == Beispiel == | ||
[[File:Vererbung-vs-hat-beziehung.png|thumb|Vererbung vs. Hat-Beziehung |817px]] | [[File:Vererbung-vs-hat-beziehung.png|thumb|Vererbung vs. Hat-Beziehung |817px]] | ||
Zeile 133: | Zeile 194: | ||
* Das <code>Rechteck</code> kann das <code>Quadrat</code> nicht zerstören, denn <code>meinRechteck</code> ist privat, also für den Nutzer von Objekten der Klasse <code>Quadrat</code> nicht sichtbar! | * Das <code>Rechteck</code> kann das <code>Quadrat</code> nicht zerstören, denn <code>meinRechteck</code> ist privat, also für den Nutzer von Objekten der Klasse <code>Quadrat</code> nicht sichtbar! | ||
<code> | <code> | ||
public class Quadrat{ | public class Quadrat{ | ||
Zeile 155: | Zeile 216: | ||
} | } | ||
} | } | ||
</code> | </code> | ||
=Vergleiche auch...= | |||
* [[Polymorphie]] | |||
* [[abstrakte Klasse]] | |||
* [[Interface]] |
Aktuelle Version vom 14. Januar 2023, 19:18 Uhr
Erklärvideo
- Vererbung, um eine bestehende Klasse zu erweitern: Beispiel AnzahlQueue
- Vererbung und Polymorphie am Beispiel Buch - Fachbuch - Hörbuch (youtube)
Fachbegriffe
s.Allgemeines, insbesondere die unterstrichenen Begriffe.
Außerdem: öffentliche Methode, öffentliches Attribut
Allgemeines
Der folgende Text ist aus Wikipedia und gekürzt.
Vererbung dient dazu, aufbauend auf existierenden Klassen neue zu schaffen. Eine neue Klasse kann dabei eine Erweiterung oder eine Einschränkung der ursprünglichen Klasse sein.
- Die vererbende Klasse wird meist Superklasse, Basisklasse oder Oberklasse genannt.
- Die erbende Klasse wird Subklasse, abgeleitete Klasse oder Unterklasse genannt.
- Den Vorgang nennt man Vererbung, weil die Subklasse alle öffentlichen Attribute und Methoden der Superklasse "erbt".
- In UML wird eine Vererbungsbeziehung durch einen Pfeil mit einer dreieckigen (leeren!) Spitze dargestellt, der von der Subklasse zur Superklasse zeigt.
- Der Subklasse stehen alle
public
-Methoden undpublic
-Attribute der Superklasse zur Verfügung. - Geerbte Attribute und Methoden werden in der Darstellung der Subklasse nicht wiederholt. Das gilt sowohl für das UML-Diagramm als auch für den Java-Quelltext.
- Abgeleitete Klasse und Basisklasse stehen typischerweise in einer "ist-ein"-Beziehung zueinander.
Beispiel 1: Buch - Fachbuch - Hörbuch
Fachbuch
"ist-ein"Buch
.Hoerbuch
auch.Buch
ist die SuperklasseFachbuch
undHoerbuch
sind die Subklassen.Fachbuch
undHoerbuch
erben vonBuch
.Fachbuch
undHoerbuch
verfügen über allepublic
-Methoden von Buch.
Implementierung
public class Buch{
private String titel;
private String autor;
public Buch(String pAutor, String pTitel){
autor = pAutor;
titel = pTitel;
}
public String gibTitel(){
return titel;
}
public String gibAutor(){
return autor;
}
/**
* info ist eine polymorphe Methode!
*/
public String info() {
String ergebnis = "Autor: "+autor+"; Titel: "+titel;
return ergebnis;
}
}
public class Fachbuch extends Buch{
private String kategorie;
public Fachbuch(String pAutor, String pTitel, String pKategorie){
// den Konstruktor von Buch aufrufen!
super(pAutor, pTitel);
kategorie = pKategorie;
}
public String gibKategorie(){
return kategorie;
}
/**
* info() ist eine polymorphe Methode
*/
public String info(){
// erst mal die info der Klasse Buch abfragen!
String ergebnis = super.info();
ergebnis += "; Kategorie: "+kategorie;
return ergebnis;
}
}
public class Hoerbuch extends Buch{
private double dauer;
private String sprecher;
public Hoerbuch(String pAutor, String pTitel, double pDauer, String pSprecher){
// den Konstruktor von Buch aufrufen!
super(pAutor, pTitel);
dauer = pDauer;
sprecher = pSprecher;
}
public double gibDauer(){
return dauer;
}
public String gibSprecher(){
return sprecher;
}
/**
* info() ist eine polymorphe Methode.
*/
public String info(){
// erst mal die info der Klasse Buch abfragen!
String ergebnis = super.info();
ergebnis += "; Dauer: "+dauer+" Sprecher: "+sprecher;
return ergebnis;
}
}
Erläuterungen:
Fachbuch
ist-einBuch
; fürHoerbuch
gilt dasselbe.- Das Schlüsselwort für Vererbung ist
extends
; damit wird eine Klasse zur Subklasse. - Im Konstruktor der Subklassen muss zuerst mit dem Schlüsselwort
super(...)
der Konstruktor der Superklasse aufgerufen werden.- D.h. zum Beispiel für
Fachbuch
: Um ein Objekt vom TypFachbuch
zu erzeugen, muss erst der Konstruktor vonBuch
aufgerufen werden; das ist auch inhaltlich wichtig, denn nur so könnentitel
undautor
richtig eingetragen werden.
- D.h. zum Beispiel für
- Mit
super.info()
greifen die Subklassen auf die Methodeinfo()
der Superklasse zu. - Dass die Methode
info()
in der Superklasse und in den Subklassen vorkommt, liegt an der Polymorphie.
Beispiel 2: StackMitAnzahl
Die Klasse StackMitAnzahl
soll genauso funktionieren wie ein Stack
.
Zusätzlich wird im StackMitAnzahl
die Anzahl der Elemente in einem Attribut anzahl
gespeichert.
Strategie
Damit StackMitAnzahl
das Attribut anzahl
immer richtig aktualisiert, müssen alle Methoden neu programmiert werden, die die Anzahl verändern, d.h. die Methoden push
und pop
.
(Bei isEmpty
und top
verändert sich die Anzahl nicht.)
Implementierung
public class StackMitAnzahl<ContentType> extends Stack<ContentType>{
private int anzahl;
// Konstruktor ist nicht unbedingt notwendig
public StackMitAnzahl(){
super();
}
public void push(ContentType pContent){
if(pContent == null){ return;}
super.push(pContent);
anzahl++;
}
public void pop(){
if(isEmpty()) { return;}
super.pop();
anzahl--;
}
// Methode, um die Anzahl auszulesen
public int getAnzahl(){
return anzahl;
}
}
Hinweise:
- Die Abbruchbedingung bei
push
ist notwendig, weil die push-Methode von Stack für pContent == null den Stack nicht verändern würde - aber anzahl würde trotzdem eins hochgezählt! - Die Abbruchbedingung bei
pop
ist notwendig, weil die pop-Methode von Stack bei einem leeren Stack nichts tut - aber anzahl würde eins verringert! D.h. man hätte eine negative Anzahl.
Vererbung vs. Hat-Beziehung
In manchen Fällen darf man Vererbung nicht verwenden, obwohl es sich um eine "ist-ein"-Beziehung handelt. Im Hinblick auf das Zentralabitur ist vor allem das folgende Kriterium wichtig:
- Können Methoden der Superklasse die Struktur der Subklasse zerstören?
In diesen Fällen ist eine Modellierung mit einer Hat-Beziehung vorzuziehen.
Beispiel
Erläuterung zur Vererbung (=links):
- Der Klasse
Quadrat
steht die MethodeaendereBreite(double pBreite)
zur Verfügung, denn sie erbt diese Methode von der SuperklasseRechteck
. - Wenn für ein Quadrat die Methode
aendereBreite(...)
aufgerufen wird, dann wird die Struktur des Quadrats zerstört - denn es ist dann kein Quadrat mehr! - D.h. Vererbung darf man hier nicht verwenden, obwohl inhaltlich eindeutig einen "ist-ein"-Beziehung vorliegt!
Erläuterung zur hat-Beziehung (=rechts):
Um die Funktionalität des Rechtecks (u.a.: die Flächenberechnung) trotzdem nutzen zu können, wird zwischen Quadrat
und Rechteck
eine hat-Beziehung hergestellt.
In der Implementierung sieht die Klasse Quadrat
dann so aus.
Quadrat
greift überall auf die entsprechende Funktionalität vonRechteck
zu.- Das
Rechteck
kann dasQuadrat
nicht zerstören, dennmeinRechteck
ist privat, also für den Nutzer von Objekten der KlasseQuadrat
nicht sichtbar!
public class Quadrat{
private Rechteck meinRechteck;
public Quadrat(double pSeite){
meinRechteck = new Rechteck(pSeite, pSeite);
}
public void aendereSeite(double pSeite){
meinRechteck.aenderLaenge(pSeite);
meinRechteck.aendereBreite(pSeite);
}
public double gibSeite(){
return meinRechteck.gibLaenge();
}
public double flaeche(){
return meinRechteck.gibFlaeche();
}
}