2013-10-18 54 views
2

我注意到一些奇怪的行爲。我有以下類:在構造函數中加載的Java屬性值在構造函數之後被還原?

public abstract class BaseFoo 
{ 
    public BaseFoo(String key) 
    { 
     Data data = Something.load(key); 
     load(data); 
    } 

    public abstract void load(Data data); 
} 


public class Foo extends BaseFoo 
{ 
    @Expose public long id = 0; 
    @Expose public String name = ""; 
    //... 

    public Foo(String key) 
    { 
     super(key); 
    } 

    @Override 
    public void load(Data data) 
    { 
    this.id = data.id; 
    this.name = data.name; 
    //snip setting misc other fields 
    } 
} 

現在,如果我做到以下幾點:

Foo f = new Foo ("abcd"); 

那麼我期待f.id包含其中裝載的Foo記錄的ID。但是,它的價值實際上是0。通過調試器運行此代碼,我發現在執行public long id = 0行之前調用Foo.load()。所以,儘管load()被調用,它不設置id等領域他們正確的價值觀,這些價值觀然後由public long id = 0;和其他變量聲明覆蓋..

我從來沒有碰到過這樣的問題之前,通常值在構造函數中設置覆蓋變量聲明中的默認值。是因爲我通過super調用了負載的值,這些值被覆蓋了嗎?如果是這樣,這是否有一個方便的解決辦法?

+0

'long'的默認值是'0L','String'是'null'。如果你做一個簡單的檢查來返回一個空字符串而不是'null',你可以通過刪除初始值來繞過這個問題。 –

+0

@JeroenVannevel這個班只是一個片段,我總共有10-12個字段。我不想做'if'檢查10-12次,以避免獲得nullpointerexceptions。 –

+0

可能重複[在構造函數中可重複方法調用有什麼問題?](http://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors) – Joe

回答

7

這是調用構造函數的虛方法的問題...

執行的順序是:

  • BaseFoo變量初始化
  • BaseFoo構造體
  • 富變量初始化
  • Foo構造函數體

該行爲在JLS, section 12.5中有詳細記錄。

所以實際上,如果你改變這些:

@Expose public long id = 0; 
@Expose public long name = ""; 

@Expose public long id; 
@Expose public String name; 

然後有條件設置name爲 「」 如果它不是已經被時間非空你進入Foo構造函數體,那麼我認爲你會沒事的。

但是,我會強烈建議您以不同的設計來解決這個問題。構造函數中的虛方法調用很快就會變得非常混亂。

+0

只是想建議http ://www.yoda.arachsys.com/csharp/constructors.html :) – Vlad

+0

如果我將'BaseFoo(String key)'重命名爲'BaseFoo',該怎麼辦?load(String key)',並從'Foo'的構造函數中執行:'load(key)',是否會導致值設置正確? –

+1

@ClickUpvote:是的,那是一種選擇。 –

相關問題