Java初始化和实例化的顺序
我试图在JVM中拼凑初始化和实例化的过程,但JLS在一些细节上有点迟钝,因此如果有人介意澄清一些细节,我们将不胜感激。这就是我到目前为止所能理解的 初始化Java初始化和实例化的顺序,java,Java,我试图在JVM中拼凑初始化和实例化的过程,但JLS在一些细节上有点迟钝,因此如果有人介意澄清一些细节,我们将不胜感激。这就是我到目前为止所能理解的 初始化 递归初始化类的静态最终变量及其作为编译时常量的接口 退出递归,按文本顺序处理静态块和静态字段 实例化 递归初始化类的最终实例变量,这些变量是编译时常量 退出递归,以文本顺序处理非静态块和实例字段,并在返回时将它们预先发送给构造函数 好的,现在开始提问 接口是否按声明的顺序处理 接口是否在单独的递归堆栈中处理 a) 如果是,接口是在超类之前还
区分类的初始化和对象的初始化很重要 类初始化 通过分配编译时常量字段,然后递归初始化超类(如果尚未初始化),然后处理静态初始值设定项(包括非编译时常量的静态字段的初始值设定项),初始化类或接口 正如您所注意到的,类的初始化本身并不会触发它实现的接口的初始化<因此,当第一次访问接口时,通常通过读取非编译时常量的字段来初始化接口。此访问可能在初始值设定项求值期间发生,从而导致递归初始化 还值得注意的是,访问编译时常量字段不会触发初始化,因为这些字段在以下位置进行计算: 对常量变量(§4.12.4)字段的引用必须在编译时解析为常量变量初始值设定项表示的值V 如果这样的字段是静态的,那么二进制文件中的代码中不应该存在对该字段的引用,包括声明该字段的类或接口。此类字段必须始终显示为已初始化(§12.4.2);绝对不能遵守字段的默认初始值(如果不同于V) 如果这样的字段是非静态的,则二进制文件中的代码中不应存在对该字段的引用,包含该字段的类除外。(它将是一个类而不是一个接口,因为接口只有静态字段。)该类应该有代码在实例创建期间将字段的值设置为V(§12.5) 对象初始化 通常通过计算类实例创建表达式来初始化对象。其进展如下:
正如我们在步骤3中看到的,对超级构造函数的显式调用只会改变调用的超级类构造函数。下面是一个在对象创建过程中打印每个步骤顺序的示例 InstanceCreateStepTest.java:
import javax.annotation.PostConstruct;
/**
* Test steps of instance creation.
*
* @author eric
* @date Jan 7, 2018 3:31:12 AM
*/
public class InstanceCreateStepTest {
public static void main(String[] args) {
new Sub().hello();
System.out.printf("%s\n", "------------");
new Sub().hello();
}
}
class Base {
static {
System.out.printf("%s - %s - %s\n", "base", "static", "block");
}
{
System.out.printf("%s - %s - %s\n", "base", "instance", "block");
}
public Base() {
System.out.printf("%s - %s\n", "base", "constructor");
}
@PostConstruct
public void init() {
System.out.printf("%s - %s\n", "base", "PostConstruct");
}
public void hello() {
System.out.printf("%s - %s\n", "base", "method");
}
}
class Sub extends Base {
static {
System.out.printf("%s - %s - %s\n", "sub", "static", "block");
}
{
System.out.printf("%s - %s - %s\n", "sub", "instance", "block");
}
public Sub() {
System.out.printf("%s - %s\n", "sub", "constructor");
}
@PostConstruct
public void init() {
System.out.printf("%s - %s\n", "sub", "PostConstruct");
}
@Override
public void hello() {
// super.hello();
System.out.printf("%s - %s\n", "sub", "method");
}
}
执行:
只需调用main方法,然后检查输出
提示:
import javax.annotation.PostConstruct;
/**
* Test steps of instance creation.
*
* @author eric
* @date Jan 7, 2018 3:31:12 AM
*/
public class InstanceCreateStepTest {
public static void main(String[] args) {
new Sub().hello();
System.out.printf("%s\n", "------------");
new Sub().hello();
}
}
class Base {
static {
System.out.printf("%s - %s - %s\n", "base", "static", "block");
}
{
System.out.printf("%s - %s - %s\n", "base", "instance", "block");
}
public Base() {
System.out.printf("%s - %s\n", "base", "constructor");
}
@PostConstruct
public void init() {
System.out.printf("%s - %s\n", "base", "PostConstruct");
}
public void hello() {
System.out.printf("%s - %s\n", "base", "method");
}
}
class Sub extends Base {
static {
System.out.printf("%s - %s - %s\n", "sub", "static", "block");
}
{
System.out.printf("%s - %s - %s\n", "sub", "instance", "block");
}
public Sub() {
System.out.printf("%s - %s\n", "sub", "constructor");
}
@PostConstruct
public void init() {
System.out.printf("%s - %s\n", "sub", "PostConstruct");
}
@Override
public void hello() {
// super.hello();
System.out.printf("%s - %s\n", "sub", "method");
}
}
- 由
标记的方法不会被调用,除非您在某个容器内调用它,比如@PostConstruct
,因为它依赖于那些容器来实现像Spring boot
@PostCo>这样的注释