2014-02-07 178 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