2013-08-09 27 views
21

Entschuldigen Sie geringfügige Syntaxfehler oder whatnot, ich erfahre dies mit einem Jitsi-Modul und nicht mit Java super vertraut werden wollen, was zu tun ist und warum und wie es behoben werden soll.Aufruf Methode aus Konstruktor

public abstract class A 
{ 
    public A() 
    { 
    this.load(); 
    } 

    protected void load() 
    { 

    } 
} 

public class B extends A 
{ 
    private String testString = null; 

    public B() 
    { 
    super(); 
    } 

    @Override 
    protected void load() 
    { 
    testString = "test"; 
    } 
} 

Die Anwendung dieses tut, wenn eine Instanz der Klasse B die Schaffung einer Lastklasse nach Name Methode:

  • Anrufe außer Kraft gesetzt Last() der Klasse B
  • Initialisiert Variablen (calls " private string testString = null "laut Debugger), nullen sie aus.

Wird dieses Java-Verhalten erwartet? Was könnte das verursachen? Es ist eine Java 1.6-Anwendung, die auf dem 1.7 JDK ausgeführt wird.

Antwort

55

Wird dieses Java-Verhalten erwartet?

Ja.

Was könnte das verursachen?

Ihr Aufruf der nicht endgültig überschriebenen Methode im nicht endgültigen Superklassenkonstruktor.

Mal sehen, was den Schritt-für-Schritt geschieht:

  • Sie eine Instanz von B erstellen.
  • B() ruft Super-Klasse Konstruktor - A(), um die Super-Klasse-Mitglieder zu initialisieren.
  • A() ruft jetzt eine nicht endgültige Methode auf, die in der Klasse B als Teil der Initialisierung überschrieben wird.
  • Da die Instanz im Kontext der Klasse B ist, ist die aufgerufene Methode load() die Klasse B.
  • load() initialisiert das Klasseninstanzfeld B - testString.
  • Der Super-Klasse Konstruktor Job beendet und kehrt (Verkettung von Konstruktor Unter der Annahme, bis Object Klasse beendet haben)
  • Der B() Konstruktor beginnt weiter ausführt, ist es selbst Mitglied zu initialisieren.
  • Als Teil des Initialisierungsprozesses überschreibt B den zuvor geschriebenen Wert in testString und initialisiert ihn erneut in null.

Moral: nie eine nicht abschließende öffentliche Methode eines nicht-final-Klasse in seinen Konstruktor aufrufen.

+21

+1 für die moralische – yshavit

+1

Große Antwort. Habe gerade viel gelernt. Vielen Dank. –

+0

Super, danke. Ich werde untersuchen, wie andere Teile des Projekts funktionieren, sie müssen es richtig machen, und das ist der Ausreißer, also werde ich dem Rest des Verhaltens der Anwendung folgen. – StrangeWill

5

Dies ist ein häufiges Problem-Muster mit Initialisierung-auf-Konstruktion und kann häufig in Infrastruktur-Code & hausgemachten DAOs gefunden werden.

Die Zuweisung zu 'null' ist nicht erforderlich & kann entfernt werden.

Wenn das als schneller Patch nicht genug ist, dann: Verschieben Sie alle Post-Construction-Init in eine separate Methode und wickeln Sie alles in einen Pseudo-Konstruktor "statische Methode" ein.

Und wenn Sie DAO-Sachen machen, ist es wirklich gut zwischen "load" und "create" zu unterscheiden, da es sich um völlig verschiedene Instanziierungen handelt. Definieren Sie separate "statische Konstruktor" Methoden & vielleicht separate interne Eingänge, für diese.

abstract public class A { 
    protected void initAfterCreate() {} 
} 

public class B { 

    @Override 
    protected void initAfterCreate() { 
     this.testString = "test"; 
    } 

    // static constructors; 
    //  --   
    static public B createB() { 
     B result = new B(); 
     result.initAfterCreate(); 
    } 
} 

Demonstrieren Last/erstellen Trennung für eine DAO:

public class Order { 
    protected int id; 
    protected boolean dbExists; 

    static public load (int id) { 
     Order result = new Order(id, true); 
     // populate from SQL query.. 
     return result; 
    } 
    static public create() { 
     // allocate a key. 
     int id = KeyAlloc.allocate("Order"); 
     Order result = new Order(id, false); 
    } 

    // internal constructor; not for external access. 
    // 
    protected Order (int id, boolean dbExists) { 
     this.id = id; 
     this.dbExists = dbExists; 
    } 
} 
+0

load() ist eine Methode, die typischerweise von Modulen verwendet wird, um ihre Konfiguration aus .properties Dateien zu ziehen. Ich habe die Basis mit der Jitsi Entwickler-Mailing-Liste berührt und wir werden sehen, was sie dafür empfohlen wird, um Konsistenz in ihrem Code zu halten (nicht alle Module laden Eigenschaften, und ich habe es satt zu sehen ... muss sowieso einen Fehler auf ihrer Liste ablegen). – StrangeWill

+0

Okay, also ist es kein DAO-Zeug. Das macht es einfacher - sollte dann nur ein Initialisierungsweg sein. 'initAfterCreate()' ist die einzige grundsätzlich zuverlässige Lösung und wird vorzugsweise in einer statischen Factory-Methode verwendet. –

+0

Warum ein Downvote? Sie teilen eine Menge tatsächlicher Erfahrung von Init-on-Construction Tangles - den praktischen Umständen, in denen sie entstehen, und effektiven Mustern ("statischer Konstruktor"), um sie zu lösen. –