初始化和实例化的Java顺序 [英] Java order of Initialization and Instantiation

查看:123
本文介绍了初始化和实例化的Java顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将JVM中的初始化和实例化过程拼凑在一起,但JLS对一些细节有点迟钝,所以如果有人想清除一些细节,我们将不胜感激。这是我迄今为止所能想到的。

I am trying to piece together the process of Initialization and Instantiation in the JVM but the JLS is a little obtuse on a few details, so if anyone would mind clearing up some details it would be appreciated. This is what I have been able to figure out so far.

初始化


  1. 递归初始化类的静态最终变量及其作为编译时常量的接口。

  1. Recursively Initialize static final variables of the class and it's interfaces that are compile time constants.

退出以文本顺序处理静态块和静态字段的递归。

Back out of the recursion processing static blocks and static fields in textual order.

实例化


  1. 递归初始化作为编译时常量的类的最终实例变量。

  1. Recursively Initialize final instance variables of the class that are compile time constants.

退出递归处理文本顺序中的非静态块和实例字段,在它返回时将它们预先添加到构造函数中。

Back out of the recursion processing non-static blocks and instance fields in textual order prepending them to the constructors as it returns.

好的,现在提问。


  1. 是按声明顺序处理的接口?

  1. are interfaces processed in order of declaration?

是在单独的递归堆栈中处理的接口吗?

are interfaces processed in a separate recursive stack?

a )如果是,接口是否得到p之前或超后rocessed?

a) if yes, do interfaces get processed before or after superclasses?

B)如果是,我在演绎着一个或他人(接口或超类)取得其非编译时常领域纠正在其他编译时常量之前初始化。

b) if yes, am I correct in deducing that one or the others (Interface or Superclass) gets its non-compile-time constant fields initialized before the others compile-time constants.

调用nondefault super()构造函数在此过程中起什么作用?

What role does calls to the nondefault super() constructor play in this process?

我的任何结论都错了吗?

Am I mistaken in any of my conclusions?

我是否遗漏了其他任何关键细节?

Am I missing any other key details?


推荐答案

区分类的初始化和对象的初始化很重要。

It is important to distinguish between the initialization of a class, and initialization of an object.

类初始化

首次访问,通过分配编译时间常量字段,然后递归初始化超类(如果尚未初始化),然后处理t静态初始化器(包括非编译时常量的静态字段的初始化器)。

A class or interface is initialized upon first access, by assigning the compile time constant fields, then recursively initializing the superclass (if not already initialized), then processing the static initializers (which include the initializers for for the static fields that are not compile time constants).

正如您所注意到的,类的初始化本身并不会触发它实现的接口的初始化。 因此,首次访问接口时,通常通过读取非编译时间常量的字段来初始化接口。在初始化程序的评估期间可能会发生此访问,导致递归初始化。

As you have noticed, initialization of a class does not, by itself, trigger initialization of the interfaces it implements. Interfaces are therefore initialized when they are first accessed, typically by reading a field that is not a compile time constant. This access may occur during evaluation of an initializer, causing a recursive initialization.

还值得注意的是,访问作为编译时常量的字段不会触发初始化,如这些是在编译时间

It is also worth noting that initialization is not triggered by accessing fields that are compile time constants, as these are evaluated at compile time:


对于作为常量变量(§4.12.4)的字段的引用必须在编译时解析为值V由常量变量的初始值表示。

A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.

如果这样的字段是静态的,那么二进制文件中的代码中不应该存在对该字段的引用,包括类或声明该字段的接口。这样的场必须总是看似已经初始化(§12.4.2);必须永远不要观察该字段的默认初始值(如果不同于V)。

If such a field is static, then no reference to the field should be present in the code in a binary file, including the class or interface which declared the field. Such a field must always appear to have been initialized (§12.4.2); the default initial value for the field (if different than V) must never be observed.

如果这样的字段是非静态的,则不应该引用该字段存在于二进制文件中的代码中,但包含该字段的类除外。 (它将是一个类而不是一个接口,因为一个接口只有静态字段。)该类应该有代码在实例创建期间将字段的值设置为V(§12.5)。

If such a field is non-static, then no reference to the field should be present in the code in a binary file, except in the class containing the field. (It will be a class rather than an interface, since an interface has only static fields.) The class should have code to set the field's value to V during instance creation (§12.5).

对象初始化

对象初始化每当创建新对象时,通常是通过评估类实例创作表达。其过程如下:

An object is initialized whenever a new object is created, typically by evaluation of a class instance creation expression. This proceeds as follows:



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

  1. Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.

如果此构造的开头是一个明确的构造函数调用(§8.8.7.1)在同一类另一个构造(使用本),则评价使用这五个相同步骤递归地构造函数调用的参数和过程。如果该构造函数调用突然完成,则此过程突然完成,原因相同;否则,继续执行步骤5.

If this constructor begins with an explicit constructor invocation (§8.8.7.1) 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.

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

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). 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.

为此类执行实例初始值设定项和实例变量初始值设定项,将实例变量初始值设定项的值分配给相应的实例变量,按从左到右的顺序,它们以文本方式出现在类的源代码中。如果执行任何这些初始值设定项导致异常,则不会处理其他初始值设定项,并且此过程会突然完成同样的异常。否则,继续执行步骤5.

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.

执行此构造函数的其余部分。如果该执行突然完成,则由于同样的原因,此过程突然完成。否则,此过程正常完成。

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.


正如我们在步骤3中看到的那样,对超级构造函数的显式调用的存在只是改变了调用哪个超类构造函数。

As we can see in step 3, the presence of an explicit call to the super constructor simply changes which super class constructor is invoked.

这篇关于初始化和实例化的Java顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆