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?

0
Richard Eng 18 Apr. 2018 im 00:00

4 Antworten

Beste Antwort

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.

2
ernest_k 17 Apr. 2018 im 21:08

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.

0
ACVM 17 Apr. 2018 im 21:07

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.

0
Daniel A. Thompson 17 Apr. 2018 im 21:08

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.)

-1
markspace 17 Apr. 2018 im 21:09