Beim Aufrufen einer überschreibbaren Methode von Konstruktoren aus
Einfach ausgedrückt ist dies falsch, weil es unnötigerweise die Möglichkeit eröffnet VIELE Ungeziefer. Wenn die @Override
aufgerufen wird, kann der Zustand des Objekts inkonsistent und/oder unvollständig sein.
Ein Zitat aus Effective Java 2nd Edition, Punkt 17: Entwerfen und dokumentieren Sie für Vererbung, oder verbieten Sie sie :
Es gibt noch ein paar weitere Einschränkungen, die eine Klasse erfüllen muss, um Vererbung zu ermöglichen. Konstruktoren dürfen keine überschreibbaren Methoden aufrufen direkt oder indirekt. Wenn Sie gegen diese Regel verstoßen, wird das Programm scheitern. Der Konstruktor der Oberklasse wird vor dem Konstruktor der Unterklasse ausgeführt, so dass die überschreibende Methode in der Unterklasse aufgerufen wird, bevor der Konstruktor der Unterklasse ausgeführt wurde. Wenn die Überschreibungsmethode von einer Initialisierung abhängt, die vom Unterklassenkonstruktor durchgeführt wird, verhält sich die Methode nicht wie erwartet.
Hier ein Beispiel zur Veranschaulichung:
public class ConstructorCallsOverride {
public static void main(String[] args) {
abstract class Base {
Base() {
overrideMe();
}
abstract void overrideMe();
}
class Child extends Base {
final int x;
Child(int x) {
this.x = x;
}
@Override
void overrideMe() {
System.out.println(x);
}
}
new Child(42); // prints "0"
}
}
Hier, wenn Base
Konstruktoraufrufe overrideMe
, Child
noch nicht die Initialisierung der final int x
und die Methode erhält den falschen Wert. Dies wird mit ziemlicher Sicherheit zu Bugs und Fehlern führen.
Verwandte Fragen
Siehe auch
Bei Objektkonstruktion mit vielen Parametern
Konstruktoren mit vielen Parametern können zu einer schlechten Lesbarkeit führen, und es gibt bessere Alternativen.
Hier ein Zitat aus Effective Java 2nd Edition, Punkt 2: Ziehen Sie ein Builder-Muster in Betracht, wenn Sie viele Konstruktorparameter haben. :
Traditionell haben die Programmierer die Teleskopkonstrukteur Muster, bei dem Sie einen Konstruktor mit nur den erforderlichen Parametern, einen weiteren mit einem einzigen optionalen Parameter, einen dritten mit zwei optionalen Parametern und so weiter bereitstellen...
Das Muster des Teleskopkonstruktors sieht im Wesentlichen wie folgt aus:
public class Telescope {
final String name;
final int levels;
final boolean isAdjustable;
public Telescope(String name) {
this(name, 5);
}
public Telescope(String name, int levels) {
this(name, levels, false);
}
public Telescope(String name, int levels, boolean isAdjustable) {
this.name = name;
this.levels = levels;
this.isAdjustable = isAdjustable;
}
}
Und jetzt können Sie eine der folgenden Aktionen durchführen:
new Telescope("X/1999");
new Telescope("X/1999", 13);
new Telescope("X/1999", 13, true);
Sie können jedoch derzeit nicht nur die name
y isAdjustable
und verlassen levels
in der Standardeinstellung. Sie können weitere Konstruktorüberladungen bereitstellen, aber natürlich würde die Anzahl mit der Anzahl der Parameter explodieren, und Sie könnten sogar mehrere boolean
y int
Argumente, die die Dinge wirklich durcheinander bringen würden.
Wie Sie sehen können, ist dieses Muster nicht angenehm zu schreiben und noch weniger angenehm zu benutzen (Was bedeutet "true" hier? Was ist 13?).
Bloch empfiehlt die Verwendung eines Bauherrenmusters, mit dem Sie stattdessen etwas wie dieses schreiben könnten:
Telescope telly = new Telescope.Builder("X/1999").setAdjustable(true).build();
Beachten Sie, dass die Parameter jetzt benannt sind und Sie sie in beliebiger Reihenfolge einstellen und diejenigen überspringen können, die Sie auf den Standardwerten belassen wollen. Dies ist sicherlich viel besser als das Teleskopieren von Konstruktoren, vor allem, wenn es eine große Anzahl von Parametern gibt, die zu vielen der gleichen Typen gehören.
Siehe auch
Verwandte Fragen