Vererbung ist ein wichtiges Konzept in der objektorientierten Programmierung. Vererbung ist neben der Komposition eine weitere wichtige Möglichkeit, die Wiederverwendbarkeit von Code zu verbessern. Wir haben in der Komposition gesehen, dass Komposition die funktionale Schnittstelle eines Objekts ist, die wiederholt aufgerufen wird. Wie wir sehen werden, ermöglicht die Vererbung die Wiederverwendung vorhandener Klassendefinitionen.
Klassenvererbung
Wenn wir zuvor eine Klasse definiert haben, haben wir bei Null angefangen und jedes Mitglied der Klasse im Detail definiert. Zum Beispiel die folgende Human-Klasse:
Kopieren Sie den Codecode wie folgt:
KlasseMensch
{
/**
*Accessor
*/
public int getHeight()
{
return this.height;
}
/**
* Mutator
*/
öffentliche Leere wachsenHöhe(int h)
{
this.height = this.height + h;
}
/**
*Atem
*/
öffentlicher leerer Atem()
{
System.out.println("hu...hu...");
}
private int-Höhe;
}
Aus der obigen Klassendefinition können wir alle Details der Klasse verstehen: die Datenmitglieder der Klasse, die Methoden der Klasse und die Schnittstelle der Klasse.
Jetzt müssen wir eine neue Klasse definieren, beispielsweise die Klasse „Frau“, und davon ausgehen, dass die Klasse „Frau“ der Klasse „Mensch“ ziemlich ähnlich ist:
Mensch & Frau
Wir können von vorne beginnen und die Woman-Klasse wie zuvor vollständig definieren:
Kopieren Sie den Codecode wie folgt:
Klasse Frau
{
/**
*Accessor
*/
public int getHeight()
{
return this.height;
}
/**
* Mutator
*/
öffentliche Leere wachsenHöhe(int h)
{
this.height = this.height + h;
}
/**
*Atem
*/
öffentlicher leerer Atem()
{
System.out.println("hu...hu...");
}
/**
* neue Methode
*/
public Human GiveBirth()
{
System.out.println("Gebären");
return (new Human(20));
}
private int-Höhe;
}
Ein Programmierer wird beim Schreiben des oben genannten Programms große Schwierigkeiten haben. Viele Definitionen wurden in der Human-Klasse geschrieben, aber wir müssen sie erneut eingeben. Die Woman-Klasse fügt lediglich eine neue Methode „giveBirth()“ hinzu (diese Methode erstellt ein neues Human-Objekt und gibt es zurück).
Mithilfe der Vererbung können wir die oben genannte Duplizierung vermeiden. Lassen Sie die Woman-Klasse von der Human-Klasse erben, und die Woman-Klasse verfügt automatisch über die Funktionen aller öffentlichen Mitglieder der Human-Klasse.
Wir verwenden das Schlüsselwort „extends“, um die Vererbung anzuzeigen:
Kopieren Sie den Codecode wie folgt:
Klasse Frau erweitert Mensch
{
/**
* neue Methode
*/
public Human GiveBirth()
{
System.out.println("Gebären");
return (new Human(20));
}
}
Dadurch ersparen wir uns viel Tipparbeit. Durch Vererbung erstellen wir eine neue Klasse, die sogenannte abgeleitete Klasse. Die geerbte Klasse (Mensch) wird als Basisklasse (Basisklasse) bezeichnet. Die abgeleitete Klasse verwendet die Basisklasse als Grundlage für ihre eigene Definition und ergänzt die Methode „giveBirth()“, die nicht in der Basisklasse definiert ist. Die Vererbungsbeziehung kann wie folgt ausgedrückt werden:
Vererbung: Der Pfeil zeigt auf die Basisklasse
Zum Testen können Sie die folgende Testklasse verwenden:
Kopieren Sie den Codecode wie folgt:
Öffentlicher Klassentest
{
public static void main(String[] args)
{
Frau aWoman = new Woman();
aWoman.growHeight(120);
System.out.println(aWoman.getHeight());
}
}
Abgeleitete Ebene
Durch Vererbung erstellen wir die Woman-Klasse. Der gesamte Prozess kann in drei Ebenen unterteilt werden: Basisklassendefinition, abgeleitete Klassendefinition und externe Verwendung.
Die Ebene der Basisklassendefinition besteht darin, eine Klasse normal zu definieren, wie beispielsweise die Definition der menschlichen Klasse oben.
Aus Sicht externer Benutzer (z. B. eines in der Testklasse erstellten Woman-Klassenobjekts) verfügt die abgeleitete Klasse über eine einheitliche externe Schnittstelle:
Für externe Benutzer ist die obige Schnittstelle ausreichend. Allein aus Sicht der Schnittstelle sind abgeleitete Klassen nichts Besonderes.
Allerdings müssen Programmierer vorsichtig sein, wenn sie auf der Ebene abgeleiteter Klassendefinitionen arbeiten:
Erstens ist die Schnittstelle gemischt: Die Methoden getHeight() und growHeight() stammen aus der Basisklasse, während die Methode GiveBirth() innerhalb der abgeleiteten Klasse definiert ist.
Es gibt weitere Komplikationen. Bisher konnten wir innerhalb der Klasse frei auf die Mitglieder der Klasse zugreifen (und damit auf das Objekt verweisen). Wenn wir uns jedoch im Definitionsbereich der Woman-Klasse befinden, können wir nicht auf die privaten Mitglieder der Basisklasse Human zugreifen. Wir erinnern uns an die Bedeutung von private: Private Mitglieder dienen nur der internen Verwendung der Klasse. Die Woman-Klasse ist eine neue Klasse, die sich von der Human-Klasse unterscheidet und daher außerhalb der Human-Klasse angesiedelt ist. In einer abgeleiteten Klasse kann nicht auf private Mitglieder der Basisklasse zugegriffen werden.
Aber das Interessante ist, dass unsere Methoden wachsenHeight() und getHeight() immer noch funktionieren. Dies zeigt, dass die privaten Mitglieder der Basisklasse existieren, wir können jedoch nicht direkt auf sie zugreifen.
Um das Konzept zu klären, müssen wir den Generierungsmechanismus abgeleiteter Klassenobjekte verstehen. Wenn wir ein Objekt einer abgeleiteten Klasse erstellen, erstellt Java zunächst tatsächlich ein Basisklassenobjekt (Unterobjekt) und fügt die anderen von der abgeleiteten Klasse definierten Mitglieder hinzu, die ein abgeleitetes Klassenobjekt bilden. Was externe Benutzer sehen können, sind die öffentlichen Mitglieder der Basisklasse und abgeleiteter Klassen. Wie unten gezeigt:
Basisklassenobjekte und abgeleitete Klassenobjekte
Die gelbe Farbe im Bild ist das Basisklassenobjekt. Mitglieder der Basisschicht können aufeinander zugreifen (verwenden Sie dies in der Human-Klassendefinition, um auf das Basisklassenobjekt zu verweisen).
Der blaue Teil ist der neue Inhalt des abgeleiteten Objekts. Ich nenne diesen Teil die abgeleitete Ebene. Die blauen und gelben Teile bilden zusammen das abgeleitete Objekt. Mitglieder der abgeleiteten Ebene können aufeinander zugreifen (dies ist in der Definition von Woman der Fall). Darüber hinaus können wir auch auf die öffentlichen Mitglieder des Basislayers zugreifen. Aus diesem Grund verwenden wir das Schlüsselwort super, um auf das Basisklassenobjekt zu verweisen, und verwenden super.member, um die Basismitglieder (öffentlich) darzustellen.
Wenn wir uns in der abgeleiteten Ebene befinden (d. h. beim Definieren der Woman-Klasse), können wir nicht auf die privaten Mitglieder der roten Basis zugreifen. Wenn wir draußen sind, können wir weder auf die violetten privaten Mitglieder der abgeleiteten Ebene noch auf die roten privaten Mitglieder der Basisebene zugreifen.
(Die privaten Mitglieder der abgeleiteten Ebene unterliegen Zugriffsbeschränkungen und sind daher mit einem Schrägstrich gekennzeichnet. Die privaten Mitglieder der Basisschicht unterliegen den meisten Zugriffsbeschränkungen und sind daher mit einem Schrägstrich gekennzeichnet.)
Super ähnelt diesem und ist ebenfalls ein impliziter Parameter. Wenn wir uns auf verschiedenen Ebenen der Klassendefinition befinden, hat dies unterschiedliche Bedeutungen. Seien Sie vorsichtig mit den Schlüsselwörtern this und super.
(Java erzwingt die Verwendung von this und super nicht. Java kann in vielen Fällen den Besitz von Mitgliedern automatisch identifizieren. Ich denke jedoch, dass dies eine gute Vorgehensweise ist.)
geschützt
Wir haben zuvor zwei zugriffsberechtigungsbezogene Schlüsselwörter eingeführt, private und public, die die externe Sichtbarkeit von Mitgliedern steuern. Jetzt führen wir ein neues Zugriffsschlüsselwort ein: protected.
Mit „geschützt“ gekennzeichnete Mitglieder sind in dieser Klasse und ihren abgeleiteten Klassen sichtbar. Dieses Konzept ist leicht zu verstehen, das heißt, auf die geschützten Mitglieder der Basisklasse kann von der abgeleiteten Ebene zugegriffen werden, von außen jedoch nicht, wie unten gezeigt:
Methodenüberschreibung
Die externe Schnittstelle des abgeleiteten Klassenobjekts besteht letztendlich aus den öffentlichen Mitgliedern des Basisklassenobjekts und den öffentlichen Mitgliedern der abgeleiteten Ebene. Wenn die öffentlichen Mitglieder der Basisklasse und die öffentlichen Mitglieder der abgeleiteten Ebene denselben Namen haben, welcher wird dann in der Java-Schnittstelle angezeigt?
Wir haben bereits in Konstruktoren und Methodenüberladung erwähnt, dass Java sowohl den Methodennamen als auch die Parameterliste verwendet, um die aufzurufende Methode zu bestimmen. Eine Methode wird durch den Methodennamen und die Parameterliste bestimmt. Wenn im obigen Problem nur die Methodennamen gleich sind, die Parameterlisten jedoch unterschiedlich sind, werden die beiden Methoden gleichzeitig der Schnittstelle angezeigt, was uns keine Probleme bereitet. Bei einem externen Aufruf entscheidet Java anhand der bereitgestellten Parameter, welche Methode verwendet werden soll (Methodenüberladung).
Was passiert, wenn der Methodenname und die Parameterliste identisch sind? Beim Ableiten der Ebene können wir auch super und this verwenden, um zu bestimmen, um welche Methode es sich handelt. Wenn wir extern sind, stellen wir nur eine einheitliche Schnittstelle dar, sodass wir nicht zwei Methoden gleichzeitig bereitstellen können. In diesem Fall rendert Java die Methoden der abgeleiteten Ebene anstelle der Methoden der Basisebene.
Dieser Mechanismus wird als Methodenüberschreibung bezeichnet. Methodenüberschreibungen können sinnvoll genutzt werden, um Methoden von Basisklassenmitgliedern zu ändern. In der abgeleiteten Ebene, also bei der Definition von Woman, können Sie beispielsweise die von der Basisklasse bereitgestellte Methode Breath() ändern:
Kopieren Sie den Codecode wie folgt:
Klasse Frau erweitert Mensch
{/**
* neue Methode
*/
public Human GiveBirth()
{
System.out.println("Gebären");
return (new Human(20));
}
/**
* Human.breath() überschreiben
*/
öffentlicher leerer Atem()
{
super.breath();
System.out.println("su...");
}
}
Beachten Sie, dass wir uns zu diesem Zeitpunkt in der abgeleiteten Ebene befinden und die Methode Breath () des Basisklassenobjekts weiterhin über Super aufrufen können. Wenn wir die Woman-Klasse extern aufrufen, können wir aufgrund einer Methodenüberschreibung die Methode des Basisklassenobjekts nicht mehr aufrufen.
Durch das Überschreiben von Methoden wird die Schnittstelle des Basisklassenobjekts verwaltet und die Implementierung der abgeleiteten Ebene verwendet.
Konstrukteur
Nachdem Sie die Konzepte von Basisklassenobjekten und abgeleiteten Ebenen verstanden haben, sind die Konstruktionsmethoden abgeleiteter Klassen leichter zu verstehen.
Wir müssen einen Konstruktor mit demselben Namen wie die Klasse in der Definition der abgeleiteten Klasse definieren. In diesem Konstruktor:
1. Da beim Erstellen eines abgeleiteten Objekts zuerst das Basisklassenobjekt erstellt und initialisiert wird, sollte zuerst der Konstruktor der Basisklasse aufgerufen werden. Wir können die super(argument list)-Anweisung verwenden, um den Konstruktor der Basisklasse aufzurufen.
2. Nachdem das Basisklassenobjekt erstellt wurde, beginnen Sie mit dem Aufbau der abgeleiteten Ebene (Initialisierung der abgeleiteten Ebenenmitglieder). Dies ist dasselbe wie die allgemeine Konstruktionsmethode, siehe Konstruktionsmethode und Methodenüberladung
Im folgenden Programm verfügt die Human-Klasse beispielsweise über einen Konstruktor:
Kopieren Sie den Codecode wie folgt:
KlasseMensch
{
/**
* Konstruktor
*/
öffentlich Mensch(int h)
{
this.height = h;
}
/**
*Accessor
*/
public int getHeight()
{
return this.height;
}
/**
* Mutator
*/
öffentliche Leere wachsenHöhe(int h)
{
this.height = this.height + h;
}
/**
*Atem
*/
öffentlicher leerer Atem()
{
System.out.println("hu...hu...");
}
private int-Höhe;
}
Die Definition der abgeleiteten Klasse Woman-Klasse und ihre Konstruktionsmethode:
Kopieren Sie den Codecode wie folgt:
Klasse Frau erweitert Mensch
{
/**
* Konstruktor
*/
öffentliche Frau(int h)
{
super(h); // Basisklassenkonstruktor
System.out.println("Hallo, Pandora!");
}
/**
* neue Methode
*/
public Human GiveBirth()
{
System.out.println("Gebären");
return (new Human(20));
}
/**
* Human.breath() überschreiben
*/
öffentlicher leerer Atem()
{
super.breath();
System.out.println("su...");
}
}
Zusammenfassen
erstreckt sich
Methode überschreiben
geschützt
super.member, super()