2014-02-07 83 views
3

我想清理一個類,它以一種我永遠不會做的方式使用初始化塊的代碼,我只是想知道我是否缺少一些信息。代碼如下所示:初始化塊vs構造函數vs變量初始化

@Entity 
class MyClass extends BaseClass { 

    @ManyToMany(fetch=FetchType.EAGER) 
    private Set<OherClass> others; 

    { 
     if (others == null) 
      others = new HashSet<OtherClass>(); 
    } 

    public MyClass(){ 
     super(); 
    } 

    //getters, setters and other stuff follows 
} 

我覺得沒有理由,更喜歡針對此上面的代碼:

@Entity 
class MyClass extends BaseClass { 

    @ManyToMany(fetch=FetchType.EAGER) 
    private Set<OherClass> others = new HashSet<OtherClass>(); 
} 

或者這樣:

@Entity 
class MyClass extends BaseClass { 

    @ManyToMany(fetch=FetchType.EAGER) 
    private Set<OherClass> others; 

    public MyClass(){ 
     this.others = new HashSet<OtherClass>(); 
    } 
} 

我問我的大學,但他唯一能夠回答的是初始化塊如何工作以及我已經知道的其他事情。我想知道,在序列化,反射,數據庫持久性,注入或任何能夠使代碼成爲必需的異常情況下,是否存在一些java(甚至是已經修復的老的)的微妙不當行爲或者框架(hibernate,spring)。

+0

重複:http://stackoverflow.com/questions/804589/use-of-initializers-vs-constructors-in-java –

+0

@kocko已經讀過,堅果我不問靜態初始化或它是如何作品。 – holap

回答

5
private Set<OherClass> others; 
{ 
    if (others == null) 
     others = new HashSet<OtherClass>(); 
} 

上面寫的代碼沒有Java語義的理解。 others == null將永遠是true。因此,這不過是寫

private Set<OherClass> others = new HashSet<OtherClass>(); 

Hibernate會確實包裹一些「魔法」,圍繞建設目標的一個非常令人費解和困惑的方式,但它仍然需要從默認的構造函數獲得一個實例。那時所有的實例初始化器都已經運行。

在更一般的音符,總是喜歡立即初始化常量表達式,甚至更好地收集值的變量,使該領域final。這對你的其他代碼來說不用擔心。

與上面你仍然有所有的選項打開如何填充該集,它可以從構造函數到構造函數不同。

+0

謝謝,這也是我的想法。但是,這段代碼太蹩腳了,我只是不確定,認爲應該有一個非常愚蠢的理由來做到這一點。或者,也許我只是希望有這樣的編碼理由。 – holap

1

我認爲這可能是有用的唯一的地方,就是當others初始化需要多於一個步驟,如果在BaseClass的構造函數被調用的方法可以通過一個子類,如MyClass但是你可以重寫要確保others已被正確初始化,因爲它被此方法使用。聽起來很複雜。我希望Java代碼,使這更清楚:

public class BaseClass { 

    public BaseClass() { 
     init(); 
    } 

    public void init() { 
     // do something... 
    } 

} 

public class MyClass extends BaseClass { 

    private Set<OtherClass> others; 
    { 
     others = new HashSet<OtherClass>(); 
     others.add(new OtherClass("hallo")); 
     // or do more complicated stuff here 
    } 

    public MyClass() { 
     super(); // explicit or may also be implicit 
    } 

    @Override 
    public void init() { 
     // use initialized others!! 
     doSomething(this.others); 
    } 

    .... 
} 

然而,這是一個非常,非常壞的模式,你永遠不應該在你的構造作爲子類中調用一個非最終還是非私有方法可能尚未正確初始化。

在那旁邊,others始終爲空,如果沒有初始化,你不必對此進行測試。

+0

好點。但正如你所提到的,從超類構造函數中調用一個子類方法肯定是一個非常糟糕的做法,還有一個更好的理由來清除它。謝謝。 – holap