JVM基础篇——类的加载过程

我们先看两个简单实例

实例1

public class Parent{

    public static int parent=0;

    static{

        System.out.println("Parent init...");

    }

}

public class Child extends Parent{

    public static int child=Parent.parent;

    static{

        System.out.println("Child init...");

    }

public Child(){

        System.out.println("Child init by constructor...");

    }

}

public class ClassLoaderTest{

    public static void main(String[]args){

        System.out.println(Child.parent);

    }

}

输出结果:

Parent init...

0

 

实例2

public class Child{

    public static Child child=Child.getInstance();

    public static int num=2;

    public static Child getInstance(){

        num++;

        System.out.println("instance:num="+num);

        returnchild;

    }

    public Child(){

        System.out.println("Child init...");

        num++;

        System.out.println("Constructor:num="+num);

    }

}

public class ClassLoaderTest{

    public static void main(String[]args){

        System.out.println("main:num="+Child.num);

    }

}

输出结果:

instance:num=1

main:num=2

这个就有点意思了,为什么instance:num不为23,而为1了?这就得从java类的加载机制说起了。容老夫细细道来。

 

类的加载机制:

类的生命周期

类在JVM中的生命周期分七个阶段:加载、验证、准备、解析、初始化、使用和卸载。其中验证、准备、解析有称为类的连接。加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,而解析可以在初始化之前也可在初始化之后,为了支持java语言的动态绑定(或者叫运行时绑定)。



加载

  • 通过类的全名获取二进制字节流

  • 字节流存入方法区

  • 堆中生成一个Class对象,作为方法区数据结构访问的入口

 

验证

  • 文件格式验证:是否满足Class文件规范

  • 元数据验证

  • 字节码验证

  • 符号引用验证

 

准备

  • 类的静态变量会在类准备阶段分配内存

  • 赋予初始值(0,null,false等),而java中显式赋值的操作是在类初始化的时候执行。

 

类的初始化

类只有在主动使用时,虚拟机才会对类进行初始化,被动使用不会初始化。

主动引用的情况:

  • New实例化

  • 访问静态变量、静态方法

  • 反射访问

  • 初始化类时,如有父类,父类也会被初始化

  • Main方法所在类会先被初始化.

被动引用的情况:

  • 调用父类静态变量,子类被称为被动引用,不会初始化。

  • 引用静态变量,定义该常量的类不会初始化

  • 数组定义类

 

现在,再回过头来分析开始提到的两个实例

实例1

1:子类调用父类的静态变量,父类会被初始化,子类不会被初始化,也就是说对于静态变量,只有直接定义该变量的类才会被初始化。所以Child.parent时,Child不会初始化,Parent初始化。

2:类的static方法在类初始化的时候会被执行(注意:是初始化时执行,而并非类加载时执行)。所以Child类的static和构造方法都不会被执行。而parentstatic方法会被执行。

 

实例2

1:类的静态变量会在类准备阶段分配内存,并赋予初始值(0null等),而java中显式赋值的操作是在类初始化的时候执行。

2:访问child.num时会触发Child的初始化,但是第一行代码child=Child.getinstance()执行时,类尚未完成初始化,所以此时num在内存中的值为0,执行++后为num=1,而当类完成初始化时,num的值又被重置为2,所以main:num=2;

3:如果将Childchild = Child.getInstance();int num = 2;换下位置,可以得到num值都为3,可自行测试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cfpl12011124

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

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

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

打赏作者

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

抵扣说明:

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

余额充值