public class A
{
private int x = 1;
A() {}
}
和
public class A
{
private int x;
A() { x = 1; }
}
,如果有的话?
如果您从实用的角度出发,那么区别在于,如果您编写许多重载构造函数,那么使用第二种初始化形式,您将不得不对编写的每个构造函数重复它。
- 在第二种情况下,你重复初始化x=0,因为它是实例变量,所以默认情况下它将初始化为0。
- 如果有多个构造函数,这可能会有所不同。
1/在初始化过程中,写的赋值在不同的时间发生——构造函数是实例初始化过程中最后执行的东西。
2/对于编译器提供的x变量,隐式初始化为零。所以两个赋值都是冗余的。
From JLS 12.5:
每当创建一个新的类实例时,都会分配内存空间为类中声明的所有实例变量留出空间类的每个超类中声明的所有实例变量类类型,包括所有可能被隐藏的实例变量。
再往下写:
就在对新创建对象的引用之前作为结果,则处理指定的构造函数以初始化new对象使用以下过程:
将构造函数的参数赋值给新创建的
如果此构造函数以显式构造函数调用开始同一类中的另一个构造函数(使用this),然后求值构造函数递归调用的参数和过程使用同样的五个步骤。如果构造函数调用完成突然地,这个过程突然地结束了,原因是一样的;
此构造函数不以显式构造函数开头调用同一类中的另一个构造函数(使用this)。如果this构造函数用于Object以外的类,然后是this构造函数将以显式或隐式调用超类构造函数(使用super)。评估论点和使用这些递归地处理超类构造函数调用同样的五个步骤。如果构造函数调用突然完成,然后,由于同样的原因,这个过程突然结束。否则,
执行实例初始化器和实例变量该类的初始化项,分配实例变量的值类中相应实例变量的初始化项从左到右的顺序,它们在源代码中以文本形式出现为了课堂。如果执行这些初始化式中的任何一个导致异常,则不再处理其他初始化式程序以同样的例外突然结束。否则,继续第5步。(在一些早期的实现中,编译器错误地省略了初始化字段的代码,如果字段初始化表达式是一个值相等的常量表达式)
执行该构造函数体的其余部分。如果这执行突然结束,那么这个过程也突然结束出于同样的原因。否则,此过程正常完成。
本质上,JVM为变量x
(以及超类的所有实例变量)创建内存,并用默认值初始化每个实例(0
为x
)。在返回类A
的新实例之前,它现在将执行构造函数体。
实际上什么都没有。类作用域中的变量,如果您自己不初始化它,它将具有初始化的默认值。对于int
类型,这将是0。这里有一个原语的默认初始化值表。
不同的是,在第二种情况下,你可以有一个构造函数
public class A
{
private int x;
A(String something) { }
}
,如果你添加了第二个构造函数,而你忘记调用this(),那么你就不会初始化你的x,让它保持默认值。所以我建议你使用第一个,因为它天生就不容易出错。
在第一种情况下,
-
不需要将变量初始化为0,因为默认情况下所有成员变量都初始化为0。
-
你不需要写一个没有参数的构造函数,因为它也是默认的。
在第二种情况下,您同样不需要将变量设置为0的构造函数。如果您想要给出0以外的值,则可能需要它,例如x=20;
在这种情况下,什么都不需要
如果x是静态的,那么它不会被初始化,直到"new A();"被编码。
由于x不是静态的,处理实际上是相同的,但是您应该注意JLS中的细微差别,特别是如果A扩展了另一个类,例如。
如果你在构造函数初始化之前对x做了一些事情(如例2),例如int b = x;不要期望b等于1。在我的脑海里,你要么在编译器上得到一个错误/警告,要么b等于零。