Was ist falsch mit überschreibbare Methode aufrufen in Konstruktoren?
Ich habe eine Wicket-Seite-Klasse, legt den Titel der Seite abhängig von dem Ergebnis einer abstrakten Methode.
public abstract class BasicPage extends WebPage {
public BasicPage() {
add(new Label("title", getTitle()));
}
protected abstract String getTitle();
}
NetBeans warnt mich mit der Meldung "Overridable method call in constructor", aber was sollte falsch mit ihm? Die einzige alternative die ich mir vorstellen kann ist die übergabe der Ergebnisse der ansonsten abstrakten Methoden der super-Konstruktor in einer Unterklasse. Aber das könnte sein, schwer zu Lesen mit vielen Parametern.
Ich bin ein .NET-Entwickler, aber sah dies ein und war daran interessiert, warum es würde davor warnen, da ich eine ähnliche Sache in Zeiten, in C#. Dieser Artikel scheint zu geben, eine Angabe darüber, warum es ist eine Warnung: javapractices.com/topic/TopicAction.do?Id=215 es ist Also alles zu tun, und wenn die Reihenfolge, in der Objekt-Hierarchie ist inialised.
In C# haben wir das gleiche problem: msdn.microsoft.com/en-us/library/ms182331.aspx
In C# haben wir das gleiche problem: msdn.microsoft.com/en-us/library/ms182331.aspx
InformationsquelleAutor deamon | 2010-08-04
Du musst angemeldet sein, um einen Kommentar abzugeben.
Auf überschreibbare Methode aufrufen von Konstruktoren
Einfach ausgedrückt, ist dies falsch, weil es unnötig eröffnet Möglichkeiten zu VIELE bugs. Wenn die
@Override
aufgerufen wird, wird der Zustand des Objekts kann sein, widersprüchlich und/oder unvollständig sind.Einem Zitat aus Effektive Java-2. Auflage, Artikel 17: Entwerfen und dokumentieren für die Vererbung oder anderes verbieten es:
Hier ein Beispiel zur Veranschaulichung:
Hier, wenn
Base
Konstruktor ruftoverrideMe
,Child
noch nicht fertig initialisiert diefinal int x
, und die Methode erhält den falschen Wert. Dies führt fast zwangsläufig zu bugs und Fehler.Fragen
Siehe auch
Auf Objekt-Konstruktion mit vielen Parametern
Konstruktoren viele Parameter führen zu schlechter Lesbarkeit und bessere alternativen vorhanden sind.
Hier ein Zitat aus Effektive Java, 2nd Edition, Artikel 2: Betrachten Sie ein builder pattern, wenn konfrontiert mit vielen Konstruktor-Parameter:
Den Teleskop-Konstruktor-Muster ist im wesentlichen so etwas wie dieses:
Und jetzt können Sie einen der folgenden Schritte aus:
Können Sie jedoch nicht, die derzeit nur die
name
undisAdjustable
, und verlassenlevels
im Verzug ist. Sie können mehrere Konstruktor-überladungen, aber offensichtlich würde die Zahl explodieren, wie die Anzahl der Parameter, die wachsen, und Sie können sogar mehrereboolean
undint
Argumente, die würden das wirklich machen ein Durcheinander von Dingen.Wie Sie sehen können, ist dies nicht eine angenehme Muster zu schreiben, und noch weniger angenehm zu bedienen ist (Was bedeutet "das wahre" hier bedeuten? Was ist 13?).
Bloch empfiehlt die Verwendung eines builder-Muster, die es erlauben würde, Sie zu schreiben, so etwas wie dies:
Beachten Sie, dass die Parameter benannt sind, und Sie können Sie in beliebiger Reihenfolge Sie wollen, und Sie können überspringen diejenigen, die Sie behalten möchten, auf default-Werte. Dies ist sicherlich viel besser als Teleskop-Konstruktoren, vor allem, wenn es eine große Anzahl von Parametern, gehören viele der gleichen Arten.
Siehe auch
Fragen
In Java-Instanz-Initialisierer wird ausgeführt bei Schritt 4, nach der superclass-Konstruktor in Schritt 3 bei der Erstellung neuer Instanzen java.sun.com/docs/books/jls/third_edition/html/... ; ich bin mir nicht sicher, ob das behebt dein Kommentar obwohl.
Das sagte, es ist schade, dass Java keine phase 2 Initialisierung: 1. Durchlauf für die Methode Definitionen, der 2. pass für die Ausführung des Konstruktors. Jetzt muss ich noch schreiben more code für die Fabrik-Fabrik-Muster oder andere. Bleh. Alles was ich wollte, war, um einige Standard-Daten von einer reinen Funktion, die vertauscht werden könnte, in einer Unterklasse oder aktualisiert zwischen bauen und zu nutzen.
Android-Ingenieure bewusst sein: das android-Ansicht überschreibbare Methode invalidate() wird manchmal auch als in-view-Konstruktor.
FYI: der zitierte Satz "Wenn Sie gegen diese Regel verstoßen, Programm-Fehler führen wird." ist eine glatte Lüge. Es ist jedoch eher Ergebnis in der Zukunft.
InformationsquelleAutor polygenelubricants
Hier ist ein Beispiel, das hilft, dies zu verstehen:
Wenn Sie diesen code ausführen, erhalten Sie die folgende Ausgabe:
Sehen Sie?
foo()
macht Gebrauch von C vor C der Konstruktor ausgeführt wurde. Wennfoo()
erfordert C, einen definierten Zustand (D. H. den Konstruktor beendet hat), dann wird es begegnen einem undefinierten Zustand in C und Dinge, die brechen kann. Und da man nicht wissen kann, in was die überschriebenfoo()
erwartet, erhalten Sie eine Warnung.InformationsquelleAutor Nordic Mainframe
Aufruf einer überschreibbaren Methode im Konstruktor ermöglicht es Unterklassen zu unterlaufen, den code, Sie können also nicht garantieren, dass es nicht mehr arbeitet. Das ist, warum Sie eine Verwarnung bekommen.
In deinem Beispiel, was passiert, wenn eine Unterklasse überschreibt
getTitle()
und gibt null zurück ?Zu "reparieren", können Sie verwenden eine die factory-Methode statt eines Konstruktors, es ist ein gemeinsames Muster von Objekten der Instanziierungen.
null
ist ein Allgemeines problem brechen viele Schnittstellen.null zurückgeben ist ein besonderes problem, wenn es geschieht in der überschriebenen Methoden, die aufgerufen werden, durch den super-Konstruktor.
ja, das ist es, was ich meinte
InformationsquelleAutor KeatsPeeks
Wenn Sie Methoden aufrufen, die in Ihrem Konstruktor, dass Sie in Unterklassen außer Kraft gesetzt, es bedeutet, dass Sie sind weniger wahrscheinlich zu sein, verweisen auf Variablen, die noch nicht existieren, wenn Sie teilen Sie Ihre Initialisierung logisch zwischen den Konstruktor und die Methode.
Haben Sie einen Blick auf diese Probe-link http://www.javapractices.com/topic/TopicAction.do?Id=215
InformationsquelleAutor Manuel Selva
Hier ist ein Beispiel, das zeigt der logische Probleme, die auftreten können, wenn der Aufruf einer überschreibbaren Methode in der super-Konstruktor.
Das Ergebnis wäre eigentlich:
minWeeklySalary: 0
maxWeeklySalary: 0
Dies ist der Konstruktor der Klasse B ruft zunächst den Konstruktor der Klasse A, wo die überschreibbare Methode in B ausgeführt. Aber innerhalb der Methode verwenden wir die Instanz-variable Faktor die noch nicht initialisiert (da der Konstruktor der Eine noch nicht fertig), also Faktor ist 0 und nicht 1 ist, und definitiv nicht 2 (die Sache, die der Programmierer könnte denken, es wird sein). Vorstellen, wie schwer würde es sein, zu verfolgen ist ein Fehler, wenn die Berechnung Logik war zehn mal mehr verdreht.
Ich hoffe, dass jemand helfen würde.
InformationsquelleAutor kirilv
In dem speziellen Fall von Wicket: das ist genau der Grund, warum ich fragte der Wicket
devs, um Unterstützung für eine explizite zwei-phase-Komponente Initialisierung im Rahmen des Lebenszyklus von der Konstruktion einer Komponente, d.h.
Gab es eine aktive Debatte darüber, ob es notwendig war oder nicht (es vollständig notwendig ist, IMHO), wie dieser link zeigt http://apache-wicket.1842946.n4.nabble.com/VOTE-WICKET-3218-Component-onInitialize-is-broken-for-Pages-td3341090i20.html)
Die gute Nachricht ist, dass die hervorragende devs bei Wicket am Ende Tat die Einführung von zwei phase-Initialisierung (machen die meisten aweseome Java-UI-framework noch Super!) also mit Wicket, die Sie tun können, alle Ihre post-Konstruktion-Initialisierung in der onInitialize-Methode, die aufgerufen wird, die das framework automatisch, wenn Sie ihn außer Kraft setzen - zu diesem Zeitpunkt im Lebenszyklus der Komponente der Konstruktor hat seine Arbeit abgeschlossen, so ist virtuelle Methoden wie erwartet arbeiten.
InformationsquelleAutor Volksman
Denke ich, Wicket, es ist besser, rufen Sie
add
Methode in deronInitialize()
(siehe Komponenten-Lebenszyklus) :InformationsquelleAutor sanluck