Java 成员初始化

Java member initialization

提问人:Luchian Grigore 提问时间:9/8/2011 最后编辑:Luchian Grigore 更新时间:3/28/2012 访问量:3364

问:

两者之间有什么区别:

public class A
{
    private int x = 1;
    A() {}
}

public class A
{
    private int x;
    A() { x = 1; }
}

,如果有的话?

爪哇岛

评论

3赞 Rn2dy 9/8/2011
我喜欢第二个,因为在面向对象的编程中,我们通过使用构造函数来实例化对象。第一个是为 var x 定义一个“类级别”初始值,第二个是定义新对象的特定初始值......无论如何,关键是良好的编程习惯有时很重要。
2赞 Rostislav Matl 3/29/2012
习惯性地提出一个问题并在回答后改变它,所以一半的答案没有意义,这是什么?
0赞 Luchian Grigore 3/29/2012
@RostislavMatl 在不需要的地方添加标签的习惯是什么?你重新标记了这个面试问题,尽管它不是。
0赞 Rostislav Matl 3/29/2012
是的,我做到了,我这样做是为了帮助别人。这是一个典型的面试问题,不管你怎么看。正如我在历史上所看到的,我并不是唯一一个这么想的人。您可能认为这也与初始化无关
1赞 Rostislav Matl 3/29/2012
当它完全改变含义时,您至少应该留下描述更改的注释。这不仅关乎你,还关乎阅读它的其他人。你了解合作和互惠的概念吗?

答:

3赞 K-ballo 9/8/2011 #1

如果你从实际的角度来看,区别在于,在第二种形式的初始化中,如果你要编写许多重载的构造函数,你将不得不对你编写的每个构造函数重复它。

评论

0赞 maks 9/8/2011
他不必在每个构造函数中重复 int 变量的初始化为零,因为它是默认值,因此它将在每个构造函数中自动初始化为零
2赞 K-ballo 9/8/2011
确实如此,但我认为他谈论的是类初始化与构造初始化。我想 0 作为初始化值只是一个糟糕的选择。
1赞 user339024 9/8/2011 #2

实际上什么都没有。类作用域的变量将初始化默认值,如果您不自己初始化它。对于类型,这将是 0。这里有一个基元的默认初始化值表。int

需要注意的是,这不适用于本地基元,您应该始终在使用前将它们初始化为一个值。

评论

0赞 phs 9/8/2011
或者更确切地说,你不能不初始化一个本地:编译器会在第一次使用时抱怨。
2赞 Android Killer 9/8/2011 #3
  1. 在第二种情况下,您重复初始化 x=0,因为它是实例变量,因此默认情况下它将初始化为 0。
  2. 如果存在多个构造函数,这可能是不同的,否则我认为没有任何其他区别。
2赞 Buhake Sindi 9/8/2011 #4

JLS 12.5 开始:

每当创建新的类实例时,都会分配内存空间 为它在类中声明的所有实例变量留出空间 类型和在 类类型,包括所有可能隐藏的实例变量。

再往下,它指出:

在对新创建的对象的引用返回为 结果,则对指示的构造函数进行处理以初始化新的 对象,使用以下过程:

  1. 将构造函数的参数分配给新创建的 此构造函数调用的参数变量。

  2. 如果此构造函数以显式构造函数调用开头 同一类中的另一个构造函数(使用此构造函数),然后计算 构造函数递归调用的参数和过程 使用相同的五个步骤。如果该构造函数调用完成 突然,然后由于同样的原因,此过程突然完成; 否则,请继续执行步骤 5。

  3. 此构造函数不以显式构造函数开头 调用同一类中的另一个构造函数(使用此)。如果 此构造函数用于 Object 以外的类,则此 构造函数将以显式或隐式调用 Superclass 构造函数(使用 super)。评估参数和 使用这些以递归方式处理超类构造函数调用 同样的五个步骤。如果该构造函数调用突然完成, 然后,由于同样的原因,此过程会突然完成。否则 继续执行步骤 4。

  4. 执行实例初始值设定项和实例变量 此类的初始值设定项,分配实例变量的值 initializers 添加到相应的实例变量中,在 它们在源代码中以文本方式出现的从左到右的顺序 对于班级。如果执行这些初始值设定项中的任何一个会导致 异常,则不会处理进一步的初始值设定项,并且 过程突然完成,但出现相同的异常。否则 继续执行步骤 5。(在一些早期的实现中,编译器 错误地省略了用于初始化字段的代码,如果该字段 初始值设定项表达式是一个值相等的常量表达式 设置为其类型的默认初始化值。

  5. 执行此构造函数主体的其余部分。如果那 执行突然完成,则此过程突然完成 出于同样的原因。否则,此过程将正常完成。

实质上,JVM 为变量(以及超类的所有实例变量)创建内存,并使用默认值 ( for ) 初始化每个实例。在返回 class 的新实例之前,它现在将执行构造函数主体。x0xA

评论

0赞 Bruno Reis 9/8/2011
哇,点赞?!问题不是在谈论静态成员!
0赞 Peter 9/8/2011 #5

不同之处在于,在第二个中,您可以有一个构造函数

public class A
{
    private int x;
    A(String something) {  }
}

如果你添加了第二个构造函数,但忘记调用this(),那么你就不会初始化你的x,而是将其保留为默认值。 因此,我建议您使用第一个,因为它本质上不太容易出现错误。

0赞 Jayy 9/8/2011 #6

在第一种情况下,

  1. 您不需要将变量初始化为 0,因为默认情况下所有成员变量都初始化为 0。

  2. 您不需要编写 no arg 构造函数,因为它也会在默认情况下给出。

在第二种情况下,您同样不需要将变量设置为 0 的构造函数。如果你想给出 0 以外的一些值,比如说x=20;

2赞 Rostislav Matl 9/8/2011 #7

1/ 在初始化期间,书面赋值发生在不同的时间 - 构造函数是实例初始化期间执行的最后一件事。

2/ 编译器提供的 x 变量隐式初始化为零。因此,这两个分配都是多余的

0赞 KRK Owner 9/20/2011 #8

在这种情况下,什么都没有。

如果 x 是静态的,那么它不会被初始化,直到编码 “new A();”。

由于 x 不是静态的,因此处理实际上是相同的,但是您应该注意 JLS 中的细微差别,例如,如果 A 扩展了另一个类。

如果您在初始化之前在构造函数中使用 x 做了一些事情(如示例 2 所示),例如 int b = x;不要指望 B 是 1。在我的脑海中,你要么在编译器上收到错误/警告,要么 b 等于零。