简体   繁体   English

Java成员初始化

[英]Java member initialization

What is the difference between: 有什么区别:

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

and

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

, if any? ,如果有的话?

如果从实际的角度提出问题,不同之处在于,对于第二种形式的初始化,您必须为您编写的每个构造函数重复它,是否要编写许多重载的构造函数。

  1. In second case you repeating the of initializing x=0 because as it is instance variable so it will be initialized to 0 by default. 在第二种情况下,您重复初始化x = 0,因为它是实例变量,因此默认情况下它将初始化为0。
  2. This can be difference if multiple constructors will be there.else i dont think any other difference. 如果有多个构造函数,那么这可能会有所不同。我不认为有任何其他区别。

From JLS 12.5 : JLS 12.5开始

Whenever a new class instance is created, memory space is allocated for it with room for all the instance variables declared in the class type and all the instance variables declared in each superclass of the class type, including all the instance variables that may be hidden. 每当创建一个新的类实例时,就会为它分配内存空间,为类类型中声明的所有实例变量提供空间,并在类类型的每个超类中声明所有实例变量,包括可能隐藏的所有实例变量。

Further down it states: 进一步下来说:

Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure: 在作为结果返回对新创建的对象的引用之前,处理指示的构造函数以使用以下过程初始化新对象:

  1. Assign the arguments for the constructor to newly created parameter variables for this constructor invocation. 将构造函数的参数分配给此构造函数调用的新创建的参数变量。

  2. If this constructor begins with an explicit constructor invocation of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. 如果此构造函数以同一个类中的另一个构造函数的显式构造函数调用开始(使用此方法),则使用这五个相同的步骤计算参数并以递归方式处理该构造函数调用。 If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; 如果该构造函数调用突然完成,则此过程突然完成,原因相同; otherwise, continue with step 5. 否则,继续步骤5。

  3. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). 此构造函数不以同一个类中的另一个构造函数的显式构造函数调用开头(使用此方法)。 If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). 如果此构造函数用于Object以外的类,则此构造函数将以超类构造函数的显式或隐式调用开始(使用super)。 Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. 使用这五个相同的步骤评估参数并递归处理超类构造函数调用。 If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. 如果该构造函数调用突然完成,则此过程突然完成,原因相同。 Otherwise, continue with step 4. 否则,继续执行步骤4。

  4. Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. 为此类执行实例初始值设定项和实例变量初始值设定项,将实例变量初始值设定项的值按从左到右的顺序分配给相应的实例变量,在这些顺序中,它们以文本方式出现在类的源代码中。 If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. 如果执行任何这些初始值设定项导致异常,则不会处理其他初始化程序,并且此过程会突然完成同样的异常。 Otherwise, continue with step 5. (In some early implementations, the compiler incorrectly omitted the code to initialize a field if the field initializer expression was a constant expression whose value was equal to the default initialization value for its type.) 否则,继续执行步骤5.(在某些早期实现中,如果字段初始值设定项表达式是一个常量表达式,其值等于其类型的默认初始化值,则编译器会错误地省略代码以初始化字段。)

  5. Execute the rest of the body of this constructor. 执行此构造函数的其余部分。 If that execution completes abruptly, then this procedure completes abruptly for the same reason. 如果执行突然完成,则此过程突然完成,原因相同。 Otherwise, this procedure completes normally. 否则,此过程正常完成。

In essence, the JVM creates memory for variable x (as well as all instance variables for superclasses) and initialize each instances with a default value ( 0 for x ). 本质上,JVM为变量x (以及超类的所有实例变量)创建内存,并使用默认值( x0 )初始化每个实例。 Before the new instance of class A is returned, it will now execute the constructor body. 在返回类A的新实例之前,它现在将执行构造函数体。

1/ The written assignments happen in different times during initialization - the constructor is the last thing executed during instance initialization. 1 /写入的赋值在初始化期间的不同时间发生 - 构造函数是在实例初始化期间执行的最后一件事。

2/ There is implicit initialization to zero for the x variable provided by compiler. 2 /编译器提供的x变量隐式初始化为零。 So both assignment are redundant . 所以两项任务都是多余的

Effectively nothing. 实际上没什么。 Variables at class-scope will have a default value initialised if you do not initialise it yourself. 如果您不自己初始化,则类范围内的变量将初始化为默认值。 For the int type, this will be 0. There's a table of default initialisation values for primitives here . 对于int类型,这将是0。有原语的默认初始化值的表在这里

It is important to note that this does not hold true for local primitives, and that you should always initialise these to a value before use. 重要的是要注意,这不适用于本地原语,并且在使用之前应始终将这些原语初始化为值。

the difference is that in the second you can have a constructor 不同的是,在第二个你可以有一个构造函数

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

and if you add the second constructor and you forget to call the this() then you dont initialise your x leaving it at its default. 如果你添加第二个构造函数而忘记调用this(),那么你就不会初始化你的x而将它保留为默认值。 So i suggest you use the first one as it is inhertly less bug prone. 所以我建议你使用第一个,因为它更容易出错。

In the first case, 在第一种情况下,

  1. You do not need to initialize the variable to 0, as by default all the member variables are initialized to 0. 您不需要将变量初始化为0,因为默认情况下所有成员变量都初始化为0。

  2. You do not need to write a no arg constructor as it will also be given by default. 您不需要编写no arg构造函数,因为默认情况下也会给出它。

In the second case, you again dont need that constructor which is setting the variable to 0. It can be needed if you want to give some value other than 0, say x=20; 在第二种情况下,你再次不需要那个将变量设置为0的构造函数。如果你想给0以外的某个值,比如x=20;可能需要它x=20;

In this case, nothing. 在这种情况下,没有。

If x was static, then it would not get initialised, until "new A();" 如果x是静态的,那么它将不会被初始化,直到“new A();” was coded. 编码。

Seeing as x is not static, the processing is effectively the same, however there are nuances in the JLS that you should be aware of, especially if A extends another class, for example. 看到x不是静态的,处理实际上是相同的,但是你应该注意JLS中的细微差别,例如,如果A扩展了另一个类。

If you did something with x in the constructor BEFORE it was initialised (as in example 2), eg int b = x; 如果你在构造函数中使用x做了一些事情,那么在初始化之前(如例2),例如int b = x; do not expect b to be 1. Off the top of my head, you'll either get an error/ warning on the compiler, or b would equal zero. 不要指望b为1.在我的头顶,你要么在编译器上得到错误/警告,要么b等于零。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM