三、类加载机制, 来自《深入理解Java虚拟机》

以下内容只是简单整理, 详细知识请阅读《深入理解Java虚拟机》一书

类加载机制

1. 类加载过程

1.1 类什么时候加载
  • 遇到new(使用new创建对象), getstatic(读取一个类型的静态字段), putstatic(设置一个类型的静态字段), 或者invokestatic(调用一个类型的静态方法)这四条字节码指令时, 如果类型没有被初始化, 则需要先触发其初始化
  • 使用Java.lang.reflect包中的方法对类型进行反射调用的时候, 如果类型没有初始化, 需要先初始化
  • 当类初始化时, 其父类没有初始化时需要先触发其父类的初始化
  • 当虚拟机启动时, 需要优先初始化包含main()方法的主类
  • 当一个接口中定义了JDK8新加入的默认方法(被default关键字修饰的接口方法)时, 他的实现类在初始化时, 该接口要先进行初始化

对于静态字段, 只有直接定义这个字段的类才会被初始化, 因此通过其子类引用父类中定义的静态字段时只会触发父类的初始化而不会触发子类的初始化

1.2 类加载的过程
  1. 加载:加载主要包括以下三件事情 1. 通过一个类的全限定名来获取定义此类的二进制字节流, 2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构, 3. 在内存中生成一个代表这个类的java.lang.Class对象, 作为这个类的各个数据的访问入口
  2. 验证:验证主要包括文件格式验证, 元数据验证, 字节码验证, 符号引用验证等
  3. 准备:准备阶段是正式为类中的变量(仅包括静态变量)分配内存并设置初始化值的阶段, 这个初始化值为类型的0值, 例如int的零值为0, long的零值为0L, boolean为false等等
  4. 解析:主要包括类或接口的解析, 字段解析, 方法解析等等
  5. 初始化:初始化阶段就是执行类构造器clinit()方法的过程
    1.clinit()方法是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并的结果, 编译器收集的顺序是语句在源文件中出现的顺序决定的, 静态语句块只能访问到定义在他之前的变量, 定义在他之后的可以赋值, 但是不能访问
    2.clinit()方法不需要显示的调用, Java虚拟机会保证在子类的clinit执行前, 父类的clinit已经执行完毕, 因此Java中第一个执行的是Object对象得到clinit方法
    3.父类的clinit先执行, 则父类的静态语句块要先于子类的变量赋值
    4.clinit并不是必须的, 如果一个类没有静态语句块, 也没有对变量的赋值操作, 可以没有clinit方法

2. 类加载器

对于任意一个类, 都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性

双亲委派机制
Java一直保持着三层类加载器, 双亲委派的类加载架构, 双亲委派模型要求除了最顶层的启动类加载器没有自己的父加载器之外, 其他加载器都应该有自己的父加载器

如果一个类加载器收到了类加载的请求, 他首先不会自己区尝试加载这个类, 而是把这个请求委派给父类加载器去完成, 每一层的类加载器都是如此, 因此所有的加载请求最后都应该会被传送到最顶层的启动类加载器中, 只有当父类反馈无法加载这个类时, 子加载器才尝试自己去完成加载

使用双亲委派机制一个好处是, Java中的类随着他的类加载器一起具备了一种带有优先级的层次关系

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值