类加载

java中的类型可以分为基本类型和引用类型,其中基本类型是由虚拟机预先定义好的。引用类型又可以分为类、接口、数组类、泛型参数,泛型参数在编译过程中会被擦除,数组类是由java虚拟机直接生成的,其他两种则有对应的字节流。类加载过程可以分为以下三个阶段:加载、链接、初始化

加载

指查找字节流(通常指.class文件),并据此创建类的过程。Java中有专门的类来处理其他类的加载工作,其顶层类加载器称作启动类加载器(Bootstrap Class-Loader),该类是用C++编写的,没有对应的Java对象,负责加载lib目录下的jar中的.class文件以及虚拟机参数-Xbootclasspath指定的类。Java中所有类加载器的父类是java.lang.ClassLoader,其子类中AppClassLoader负责加载应用程序路径下的类(虚拟机参数-cp/-classpath、系统变量java.class.path或环境变量CLASSPATH所指定的路径),ExtClassLoader负责加载lib/ext目录下的jar中的.class文件以及系统变量java.ext.dirs指定的类;其加载过程是由子类先委托给父类加载器,父加载器没有加载到,子类再自己去加载,通常我们把这种方式叫作“双亲委派模型”。在Java虚拟机中,类的唯一性是由类加载器实例以及类的全名一同确定的,可以通过这一特性来实现运行同一个类的不同版本。

链接

指将创建成的类合并至虚拟机中,使之能执行的过程。这个阶段可以细分为验证、准备、解析。

  • 验证

         确保被加载的类满足虚拟机的规范。通常编译器生成的类文件是满足的,但是可以通过字节码注入修改类文件信息。

  • 准备

         为被加载类的静态字段分配内存,部分虚拟机会在该阶段构造其他跟类层次相关的数据结构,比如说用来实现虚方法的动态绑定的方发表。

  • 解析

        在class文件被加载至虚拟机之前,这个类无法知道其他类及其方法、字段所对应的具体地址,甚至不知道自己方法、字段的地址。因此,每当需要引用这些成员时,编译器会生成一个符号引用。在运行阶段,这个符号引用一般都能够无歧义的定位到目标上。

        该阶段正是将这些符号引用解析成为实际引用。如果符号引用指向一个未被加载类的字段或方法,那么会触发这个类的加载(不一定会触发类的链接和初始化),实际上Java虚拟机规范并没有要求在链接过程中完成解析。仅规定:如果某些字节码使用了符号引用,那么在执行这些字节码之前,需要完成对这些符号引用的解析。

初始化

在Java代码中,如果要初始化一个静态字段,我们可以在声明时直接赋值,也可以在静态代码块中对其进行赋值。

如果直接赋值的静态字段被final修饰,并且它的类型是基本类型或字符串时,那么该字段会被java编译器标记为常量值,其初始化直接由虚拟机完成。其他直接赋值操作,以及静态代码块中的赋值,会被java编译器置于同一方法中,<clinit>。

类加载的最后一步是初始化,便是为标记为常量值的字段赋值,以及执行<clinit>方法的过程。虚拟机会通过加锁的手段来保证该方法仅被执行一次,只有初始化完成后,该类才可被执行。

以下几种情况会触发类的初始化:

  1. 虚拟机启动时,初始化用户指定的类;
  2. new指令,初始化指令对应的类;
  3. 调用静态方法,初始化该静态方法所在类;
  4. 访问静态字段,初始化该字段所在类;
  5. 子类的初始化会触发父类的初始化;
  6. 如果一个接口定义了default方法,那么直接实现或间接实现该接口的类的初始化,会触发该接口的初始化;
  7. 使用反射对某个类进行调用时,初始化该类;
  8. 当初次调用MethodHandle实例时,初始化该MethodHandle指向的方法所在的类;

ps:文中所述为本人读书笔记,如有哪里不对,还请指出,谢谢~!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值