《深入理解JVM》7-类加载

从Class文件到类的过程要经过

  1. 加载-
  2. 链接-
  3. 初始化

三个过程。根据上一节讲到的内容,java语言中分为基本类型和引用类型

基本类型是虚拟机预先定义好的,引用类型分为数组-类-接口。数组也是虚拟机直接生成的,只有类和接口对应的是字节流(操作码流)

操作码可以是class文件形式,也可以是网络上读取,也可以是机器内部生成。我们以常见的class文件为例。

加载

查找类文件,并读取字节码到内存

双亲委派机制

jvm提供了默认的三个类加载器

  1. 启动类加载器(boot strap classLoader),最顶级,是C++代码实现,所以获取不到,null代替。加载jre路径下 lib目录下的类
  2. 扩展类加载器(extension class loader),启动类加载器的子类,加载 jre下lib/ext目录下的类
  3. 应用类加载器 (application class loader),扩展类加载器的子类,加载应用相关的jar包等。

比如有这样一个需求,需要加载com.david.study.test.Demo.class文件。首先获取当前线程的类加载器A,然后逐级向上查找父加载器,看父加载器能否加载到Demo文件,如果可以,给内存中的Demo类取唯一符号:类加载器+类全路径名。如果父加载器加载不到类,就自己取查找文件。

注意:如果一个类被不同的加载器加载,jvm会认为两个类不是同一个类。用户也可以自定义类加载器

链接

  1. 验证:验证class字节码是否符合虚拟机标准(版本号,magic no等)

  2. 准备:准备给类的静态变量分配存储空间,构建实现虚方法动态绑定的方法表。还有调用本类的方法和属性,并不知道具体的地址,所以只能保存为目标类的名称+方法+参数+返回值这样组成的符号引用,

  3. 解析:把字节码当中的符号引用解析为实际地址,比如调用B对象的update方法,之前只知道update的符号地址,现在要解析为jvm中B类update的实际地址。

初始化

类中的静态字段或静态代码段,在初始化阶段给予赋值及执行,这些被集中放置在<clinit>方法中。java虚拟机在执行<clinit>方法时会加锁,保证只执行一次。

调用初始化的时机:

  1. 程序启动时,初始化主类
  2. new 命令
  3. 访问静态方法或静态属性
  4. 子类初始化会出发父类初始化
  5. 使用Api反射
  6. MethodHandle实例执行时

猜你喜欢

转载自blog.csdn.net/David_lou/article/details/109075278
今日推荐