2011-01-13 61 views
5

我个人非常喜欢实例初始化器 - 我使用它们为集合等事物分配默认值,所以在编写构造函数时,我不必记住每次都为它们分配相同的默认值。对我而言,这看起来很优雅 - 避免了NPE出现令人讨厌的问题,避免了重复的代码。私有方法看起来并不好,因为a)它不能将值赋给final字段,b)它可能在代码中的其他地方运行,c)仍然需要在每个构造函数的开始时显式调用该方法。实例初始化器是否被认为是坏风格?

但是,与他人谈话的另一面是他们很混淆,一些读代码的人可能不明白他们做什么或什么时候被调用,因此他们可能会导致比他们解决更多的问题。

是否正确使用这些初始值设定项需要鼓励或避免?或者它是“各自为战”的情况?

+3

没有语言功能是“好”还是“坏” - 所有事情都有一个真正闪耀的情形。我认为更好的问题是“在什么情况下要避免或使用实例初始化器?” – templatetypedef 2011-01-13 01:45:47

+1

你几乎总是希望集合类型的字段是'final',它解决了那些NPE问题。 – 2011-01-13 02:35:24

回答

3

这取决于,例如在你的代码的Java的读者知识水平,可以预计将有和方案是否切实可行。

替代品有:

  • 内嵌到每一个构造函数。如果有几个构造函数,则违反了DRY。
  • 将所有构造函数委托给相同的构造函数,并将代码放入该构造函数中。如果构造函数不平凡并且采用不同的参数,则可能需要编写一个新的构造函数,该构造函数接收参数中所有字段的值。如果有许多字段,这可能会相当长(并且很难阅读,因为哪个值分配给哪个字段并不明显)
  • 所有构造函数都调用init方法。无法以这种方式分配最终字段。应该可能防止该方法被覆盖。可能要防止它被多次调用。

由于初始值设定项并不常见,所以只有在明确使用它们的优点时才应该使用它们。我最近使用的一个是:

private final Collator collator = Collator.getInstance(); 
{ 
    collator.setStrength(Collator.SECONDARY); 
} 

在一个类中有几个构造函数具有相当不同的参数列表和六个其他字段。

0

您可以使用带参数的构造函数,并且此构造函数调用私人setter。而不是实现一个用默认值调用该构造函数的默认构造函数。如果您想要将默认值分配给属性,请在声明中执行。

实例和静态初始化器对初始化复杂数据结构(如矩阵或立方体)很有用。

顺便说一句,最后的属性大多数时候被称为常量。

1

我真的不使用他们,但一个情况下,我可以看到他们有用的是当你有多个构造函数,而不是自称(这个(..)),需要一些常见的初始化逻辑共享,并且无需创建一个特定的私人方法。 哦,唯一的地方,我用实例初始化是在一个在线地图,例如,如快速初始化:

Map<String,String> m = new HashMap<String,String>(){{ 
    put("a","b"); 
    put("c","b"); 
    put("d","b"); 
}}; 

可能是我们说的接口

interface A { 

    Map<String,String> PROPS = Collections.unmodifiableMap(new HashMap<String,String>(){{ 
     put("a","b"); 
     put("c","b"); 
     put("d","b"); 
    }}); 
} 

有用初始化地图不过这样做你最终的HashMap的annonymous子...

1

这是更好地超载的构造,并有尽可能多的构造变化,只要你喜欢。 Java的Arraylist就是最好的例子。它有两个构造函数。一个将整数作为参数,另一个作为默认构造函数。如果你看一下默认的构造函数,它调用逸岸具有恒定值的单参数的构造函数10.

List<Object> x = new ArrayList<Object>(); //Creates with default capacity 10 
List<Object> y = new ArrayList<Object>(40); //Creates with the specified capacity 40 
1

我会留他们是首选。但基于其他的回应,它似乎可能更“每个人都有自己的”。我喜欢他们,因为它将相关信息保存在一起。而不是声明一个值并在构造函数中设置它,你可以在一个地方完成所有的工作。

相关问题