4

以下两者有什么区别,哪个更可取?

public class foo {

    int i = 2;

}

public class foo {

  int i;
    foo() {

        i = 2;

    }
}
4

5 回答 5

4

在您的示例中,行为语义没有区别。在 Java 中,所有实例字段初始化器(和实例块)都在超类初始化之后、构造函数体之前执行;见JLS 12.5

区别在于代码的可读性和(在其他示例中)避免重复编码和脆弱性1。这些需要根据具体情况进行评估。

还值得注意的是,在某些情况下您必须在构造函数中进行初始化;即当初始化依赖于构造函数参数时。


1 - 重复性和脆弱性问题是同一件事的反面。如果您有多个构造函数,“在构造函数中初始化”方法往往会导致重复。如果您添加额外的字段,您可能会将初始化添加到所有相关的构造函数;即脆弱性。

于 2013-02-25T11:52:02.440 回答
1

如果您有两个或多个构造函数并且每个构造函数的初始化值不同,那么您应该使用构造函数初始化,因为没有办法对成员初始化做同样的事情......

但是,如果您只有一个构造函数……您可以使用成员初始化来提高代码清晰度……

于 2013-02-25T11:32:32.393 回答
0

首先,我认为第二个示例应如下所示:

public class foo{

  int i;
  foo(){

     i = 0;

  }

}

否则 i 只是 C'tor 范围内的局部变量。其次,第一个示例显示了在调用类 C'tor 之前调用的初始化。如果无论使用什么 C'tor 都希望发生这种情况,这很好。它还使您能够将 i 声明为只读。

于 2013-02-25T11:33:26.097 回答
0

特别是在这种情况下,这两种变体没有区别。第一个变体更可取,因为构造函数内部字段的初始化,像往常一样,使用来自构造函数参数的外部值。

于 2013-02-25T11:34:56.243 回答
0

在您的第一个示例中,i 是类 foo 的实例变量(更好的名称是 Foo)。它在类加载时初始化。

在您的第二个示例中, i也是一个实例变量,但在这种情况下是在 foo() 构造函数中初始化的。

这里没有真正的区别,尤其是对于原语。

但是,在多线程环境中,如果您确实打算在构造函数中初始化 ivars,并且这些 ivars 是非原始的,则需要避免暴露部分构造对象的风险。这样做的原因是构造函数不同步并且不能synchronised应用关键字,但是两个线程不能构造同一个对象。

因此,为避免这种情况,您永远不应该this在构造函数中公开。这样做的一种方法是调用非最终方法。这样做,比如说调用一个抽象方法,允许一些未知的代码对你未完成的对象做一些事情。显然,如果您在声明中进行初始化,则无法做到这一点。

ps我认为在Effective Java中有一些东西,但找不到任何东西。

于 2013-02-25T11:32:37.007 回答