2013-08-09 14 views
21

Przepraszam za wszelkie pomniejsze błędy składni lub cokolwiek, mam tego z modułem Jitsi i niezbyt dobrze obeznana z Javą chcę potwierdzić, co się dzieje i dlaczego i jak to naprawić.Metoda wywołania z konstruktora

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"; 
    } 
} 

Aplikacja robi to podczas tworzenia instancji klasy B przy użyciu klasy obciążenia metodą nazwisko:

  • zwraca nadpisane load() w klasie B
  • Inicjuje zmiennych (połączeń " private string testString = null "według debuggera), zerując je.

Czy to oczekiwane zachowanie Java? Co może spowodować to? Jest to aplikacja Java 1.6 uruchomiona na 1.7 JDK.

Odpowiedz

55

Czy to oczekiwane zachowanie Java?

Tak.

Co może spowodować?

Twoje wywołanie metody nieokreślonej nadrzędnej w niefinałowym konstruktorze super klasy.

Zobaczmy, co się dzieje krok po kroku:

  • utworzyć instancję B.
  • B() dzwoni super konstruktor klasy - A(), aby zainicjować członków super klasy.
  • teraz wywołuje nieostateczną metodę, która jest nadpisywana w klasie B, jako część inicjalizacji.
  • Ponieważ instancja w kontekście jest klasy B, wywoływana jest metoda load() klasy B.
  • load() inicjuje pole instancji klasy B - testString.
  • super konstruktor klasy zakończy pracę i powróci (Zakładając łańcuchowym konstruktora do Object klasy były gotowe)
  • Konstruktor B() rozpoczyna wykonywanie dalej, inicjowanie własną członkiem.
  • Teraz, w ramach procesu initilization, B nadpisuje poprzednią zapisaną wartość w testString i ponownie inicjuje ją do null.

Moralne: Nigdy nie wywołaj nieostatecznej metody publicznej klasy nieostatecznej w jej konstruktorze.

+21

+1 dla moralnego – yshavit

+1

Wielkiej odpowiedź. Dużo się nauczyłem. Dziękuję Ci. –

+0

Niesamowite, dzięki. Zbadam, w jaki sposób działają inne części projektu, muszą to zrobić dobrze, a to jest odstająca część, więc postąpię zgodnie z resztą zachowania aplikacji. – StrangeWill

5

Jest to typowy wzorzec problemów z inicjalizacją na budowie i często można go znaleźć w kodzie infrastruktury & DAOs domowej roboty.

Przydział do "null" jest niepotrzebny & może zostać usunięty.

Jeśli to nie wystarczy jako łatka szybka, to: Przenieś cały proces poinstalacyjny do osobnej metody i zawiń go w pseudo-konstruktor "metody statycznej".

A jeśli robisz rzeczy DAO, naprawdę dobrze jest odróżnić "załaduj" i "utwórz", ponieważ są to zupełnie różne wystąpienia. Zdefiniuj osobne "konstruktory statyczne", być może oddzielne wewnętrzne inicjały dla nich.

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(); 
    } 
} 

Wykazanie obciążenia/tworzyć separacji dla 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() to metoda używana zwykle przez moduły do ​​wyciągania konfiguracji z plików .properties. Dotknąłem bazy z listą mailingową Jitsi dev, a zobaczymy, jakie jest ich zalecane podejście, aby zachować spójność w ich kodzie (nie wszystkie moduły ładują właściwości, a ja zmęczyłem się szukaniem ... i tak muszę zgłosić błąd na ich liście). – StrangeWill

+0

Okay, więc to nie jest DAO. Dzięki temu będzie łatwiej - powinna to być jedna ścieżka inicjalizacji. 'initAfterCreate()' jest jedynym fundamentalnie niezawodnym rozwiązaniem i najlepiej zawija je w statycznej metodzie fabrycznej. –

+0

Dlaczego downstream? Dzielenie się wieloma faktycznymi doświadczeniami splątków init-on-construction - praktycznymi okolicznościami, w których się pojawiają, oraz efektywnymi wzorcami ("konstruktor statyczny") w celu ich rozwiązania. –

Powiązane problemy