以下两者有什么区别,哪个更可取?
public class foo {
int i = 2;
}
public class foo {
int i;
foo() {
i = 2;
}
}
以下两者有什么区别,哪个更可取?
public class foo {
int i = 2;
}
public class foo {
int i;
foo() {
i = 2;
}
}
在您的示例中,行为语义没有区别。在 Java 中,所有实例字段初始化器(和实例块)都在超类初始化之后、构造函数体之前执行;见JLS 12.5。
区别在于代码的可读性和(在其他示例中)避免重复编码和脆弱性1。这些需要根据具体情况进行评估。
还值得注意的是,在某些情况下您必须在构造函数中进行初始化;即当初始化依赖于构造函数参数时。
1 - 重复性和脆弱性问题是同一件事的反面。如果您有多个构造函数,“在构造函数中初始化”方法往往会导致重复。如果您添加额外的字段,您可能会将初始化添加到所有相关的构造函数;即脆弱性。
如果您有两个或多个构造函数并且每个构造函数的初始化值不同,那么您应该使用构造函数初始化,因为没有办法对成员初始化做同样的事情......
但是,如果您只有一个构造函数……您可以使用成员初始化来提高代码清晰度……
首先,我认为第二个示例应如下所示:
public class foo{
int i;
foo(){
i = 0;
}
}
否则 i 只是 C'tor 范围内的局部变量。其次,第一个示例显示了在调用类 C'tor 之前调用的初始化。如果无论使用什么 C'tor 都希望发生这种情况,这很好。它还使您能够将 i 声明为只读。
特别是在这种情况下,这两种变体没有区别。第一个变体更可取,因为构造函数内部字段的初始化,像往常一样,使用来自构造函数参数的外部值。
在您的第一个示例中,i 是类 foo 的实例变量(更好的名称是 Foo)。它在类加载时初始化。
在您的第二个示例中, i也是一个实例变量,但在这种情况下是在 foo() 构造函数中初始化的。
这里没有真正的区别,尤其是对于原语。
但是,在多线程环境中,如果您确实打算在构造函数中初始化 ivars,并且这些 ivars 是非原始的,则需要避免暴露部分构造对象的风险。这样做的原因是构造函数不同步并且不能synchronised
应用关键字,但是两个线程不能构造同一个对象。
因此,为避免这种情况,您永远不应该this
在构造函数中公开。这样做的一种方法是调用非最终方法。这样做,比如说调用一个抽象方法,允许一些未知的代码对你未完成的对象做一些事情。显然,如果您在声明中进行初始化,则无法做到这一点。
ps我认为在Effective Java中有一些东西,但找不到任何东西。