Angenommen, Sie haben diese Klasse:
import java.util.ArrayList;
public class Array
{
private ArrayList<Object> a = new ArrayList<Object>();
public void add(Object element)
{
a.add(element);
}
public void addAll(Object elements[])
{
for (int i = 0; i < elements.length; ++i)
a.add(elements[i]); // this line is going to be changed
}
}
Und diese abgeleitete Klasse:
public class ArrayCount extends Array
{
private int count = 0;
@Override
public void add(Object element)
{
super.add(element);
++count;
}
@Override
public void addAll(Object elements[])
{
super.addAll(elements);
count += elements.length;
}
}
In der Basisklasse nehmen wir folgende Änderung vor:
public void addAll(Object elements[])
{
for (int i = 0; i < elements.length; ++i)
add(elements[i]); // this line was changed
}
Ich würde erwarten, dass die add () -Methode in der Basisklasse aufgerufen wird, nicht die überschriebene add () in der abgeleiteten Klasse. Warum ist das nicht der Fall? Und ist dieses Beispiel ein Missbrauch von OOP?
4 Antworten
Java ruft immer die Methodenimplementierung der Laufzeitklasse (die reale Objektklasse zur Laufzeit) auf, sofern es sich um eine gültige Methodenüberschreibung handelt. Das nennt man dynamische Bindung.
Sie missbrauchen nicht, sondern nutzen eine garantierte Funktion.
Was Sie als Design haben, ist in Java legal, aber aus vielen Gründen eine schlechte Praxis, von denen Sie eine wichtige hervorgehoben haben. Dies ist einer der Hauptgründe, warum die Vererbung von Implementierungen manchmal zugunsten der Vererbung von Schnittstellen nicht empfohlen wird.
Am Ende des Tages läuft es darauf hinaus, was zur Laufzeit passiert.
Da die Funktion add()
ist, wird das Objekt add()
für this
aufgerufen, das zur Laufzeit die überschriebene Funktion ist.
Dies ist der springende Punkt bei der Kapselung. Eine untergeordnete Klasse sollte die vollständige Kontrolle darüber haben, was ihre Methoden tun.
Ich würde erwarten, dass die add () -Methode in der Basisklasse aufgerufen wird, nicht die überschriebene add () in der abgeleiteten Klasse. Warum ist das nicht der Fall?
Java verwendet den dynamischen Versand, auch als dynamische Bindung bezeichnet, um Methoden zur Laufzeit zu binden. In einfachen Worten bedeutet dies, dass beim Aufrufen einer Methode für eine Basisklasse die Methode ausgeführt wird, die dem tatsächlichen Typ des Objekts entspricht. Siehe den Wikipedia-Artikel oder den Java-Referenz zum Polymorphismus.
Ist dieses Beispiel ein Missbrauch von OOP?
Für ein erfundenes Beispiel, das den dynamischen Versand demonstriert, ist es nicht schlecht. Für alles andere ist es sinnlos.
Ich denke, die folgende Änderung behebt das Problem:
In der Basisklasse nehmen wir folgende Änderung vor:
public void addAll(Object elements[])
{
for (int i = 0; i < elements.length; ++i)
super.add(elements[i]); // <-- new use of SUPER
}
Wenn Sie möchten, dass bestimmte Methoden unveränderlich sind (immer dasselbe tun), müssen Sie sie grundsätzlich final
deklarieren, um ein Überschreiben zu verhindern. Andernfalls kann eine abgeleitete Klasse alles implementieren, was sie will.
(Die Lösung für that besteht darin, eine Dokumentation zu schreiben, in der erläutert wird, wie der Vertrag lautet, dem jede abgeleitete Methode folgen muss.)
Neue Fragen
java
Java ist eine Programmiersprache auf hoher Ebene. Verwenden Sie dieses Tag, wenn Sie Probleme haben, die Sprache selbst zu verwenden oder zu verstehen. Dieses Tag wird selten alleine verwendet und wird am häufigsten in Verbindung mit [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] und [maven] verwendet.