【JVM】底层实现(三):对象初始化流程 --init 方法、cinit 方法

Java 的两种类内变量初始化方式:

  • 成员变量:在实例构造器<init>方法中进行,比如 int x = 1
  • 类变量:在类构造器 <cinit> 方法中或者使用 class ConstantValue 属性,static int x = 1:

这里再多说一句,对于 static 变量的初始化,目前 Sun Javac 编译器的选择是:如果同时使用 final 和 static 来修饰一个变量,并且这个变量的数据类型是基本类型或者 java.lang.String 的话,就生成 ConstantValue 属性来进行初始化,如果这个变量没有被 final 修饰,或者并非基本类型及字符串,则将会选择在 方法中进行初始化。

注意,接口中的属性都是static final类型的常量,因此在准备阶段就已经初始化

1.init 方法

Java 在编译之后会在字节码文件中生成<init>方法,称之为实例构造器,作用是初始化所有成员变量。

该实例构造器是由编译器自动生成,详细点说就是,将类中所有成员变量的赋值动作和语句块({}),全部收集到<init>方法一起执行。收集的一般顺序为:

  1. 父类变量初始化
  2. 父类语句块
  3. 父类构造函数
  4. 子类变量初始化
  5. 子类语句块
  6. 子类构造函数

<init> 方法的执行时机是代码中 new 一个对象,比如 new A()。

2. cinit 方法

Java 在编译之后会在字节码文件中生成<cinit>方法,称之为类构造器,作用是初始化所有类变量。

类构造器同实例构造器一样,都是有方法是由编译器自动生成,收集类的是所有类变量的赋值动作,和静态语句块(static{}块)中的语句。收集的一般顺序为:

  1. 父类静态变量初始化
  2. 父类静态语句块
  3. 子类静态变量初始化
  4. 子类静态语句块

<cinit> 方法的执行时机是 JVM 将 class 字节码文加载进来,初始化静态变量时。

两点注意:

  • 虚拟机中第一个被执行的<cinit>方法的类肯定是 java.lang.Object,因为它是说有类的父类(基类)
  • 接口中不能使用静态语句块,但仍然有变量初始化的赋值操作,因此接口与类一样都会生成<cinit>方法。 但接口与类不同的是,执行接口的<cinit>方法不需要先执行父接口的<cinit>方法。 只有当父接口中定义的变量使用时,父接口才会初始化。 另外,接口的实现类在初始化时也一样不会执行接口的<cinit>方法。

3.对象初始化流程

<cinit> 方法是在类加载过程中执行的,而<init>是在对象实例化执行的,所以<cinit>一定比<init>先执行。所以整个顺序就是:

  1. 父类静态变量初始化
  2. 父类静态语句块
  3. 子类静态变量初始化
  4. 子类静态语句块
  5. 父类变量初始化
  6. 父类语句块
  7. 父类构造函数
  8. 子类变量初始化
  9. 子类语句块
  10. 子类构造函数

代码示例

// 父类
public class Parent {
	// 父类静态变量,及初始值
    static int a = 1;
    // 父类成员变量,及初始值
    int b = 1;
    // 父类静态代码块
    static {
        System.out.println("parent static block(a):" + (++a));
    }
    // 父类普通代码块
    {
        System.out.println("parent  block(b):" + (++b));
    }
    public Parent() {
        System.out.println("parent construction");
    }
}
// 子类
public class Child extends Parent {
	// 还是 a、b
    static int a = 1;
    int b = 1;
    static {
        System.out.println("child static block(a):" + (++a));
    }
    {
        System.out.println("child  block(b):" + (++b));
    }
    public Child() {
        System.out.println("child construction");
    }
	
	// 入口
    public static void main(String[] args) {
        new Child();
    }
}

最终结果

parent static block(a):2 
child static block(a):2 // 虽然在父类已经成 2 了,但是在子类又初始化了
parent  block(b):2 		// 父类代码块
parent construction 	// 父类构造函数
child  block(b):2		
child construction

参考链接:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A minor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值