《Java高并发编程详解-多线程架构与设计》Java Classloader

摘自《Java高并发编程详解-多线程架构与设计》第九章 p144-p157
Java语言规范

文章目录

    • 重点:
    • 1.类加载的三个过程-简述
    • 2. 类的主动使用和被动使用
      • 主动使用的场景-new,反射,使用静态部分,子导致父初始化
      • 被动使用
    • 3. 类的加载过程详解
      • 3.1 类的加载阶段
      • 3.2 类的连接阶段
        • 验证
        • 元数据:确保class符合jvm规范。语义验证。
        • 准备
        • 解析
        • 初始化
    • 类加载过程实例剖析

重点:

  1. 连接-准备阶段为静态变量赋初值,初始化阶段为静态变量赋代码值
  2. 引起初始化阶段的6种情况(主动引用),静态变量/方法,new,反射,子类引起父类。
  3. 被动引用,如静态常量。其值copy到被引用的类。
  4. 类加载的三个阶段
  5. 静态代码块可以对后面的静态变量赋值,但不能访问。
  6. clinit线程安全

1.类加载的三个过程-简述

  1. 加载阶段
    查找并加载class文件
    loadClass from somewhere -> getClassBytes and defineClass->return Class
    常见异常:ClassNotFoundException,NoClassDefFoundError

  2. 连接阶段
    a. 验证
    确保类文件正确性。如class版本,魔数 CAFEBABE
    b. 准备-赋初始值
    为类的静态变量 分配内存,初始化【默认值】。
    c. 解析
    将类中符号引用转为直接引用。
    如引用了其他类, 则其他类先要经历类的所有加载过程。

  3. 初始化阶段 ()-赋代码值
    class initailze为类的静态变量赋予正确的值(代码编写时指定的值)

2. 类的主动使用和被动使用

JVM虚拟机规定,类和接口被java程序首次主动使用才会对其进行初始化。

主动使用的场景-new,反射,使用静态部分,子导致父初始化

  1. new
  2. 访问类的静态变量
  3. 访问类的静态方法
  4. 对类进行反射操作 。 如 Class.forName(“xx”); 参考java.sql.driver初始化驱动时调用DriverManager注册driver。ps:ClassLoader.loadClass不会触发【连接-初始化阶段】,只会触发【加载阶段】。
  5. 初始化子类导致父类的初始化
    同理, 调用子类的静态变量会导致父类的初始化。

《Java高并发编程详解-多线程架构与设计》Java Classloader_第1张图片
6. 启动类:执行main锁在的类会导致该类的初始化

《Java高并发编程详解-多线程架构与设计》Java Classloader_第2张图片

除了上述6种,其他的都为被动使用,不会导致类的【加载】和【初始化】。

《Java高并发编程详解-多线程架构与设计》Java Classloader_第3张图片

被动使用

  1. 引用类的静态常量
    ps:静态常量会在编译期间被计算出来copy到其他类,可使用javap查看class文件

  2. 声明数组

3. 类的加载过程详解

例子
《Java高并发编程详解-多线程架构与设计》Java Classloader_第4张图片

《Java高并发编程详解-多线程架构与设计》Java Classloader_第5张图片

3.1 类的加载阶段

关键:1.得到class对应的二进制流(不限方式)2.defineClass

类的加载最终产物是堆内存中的class对象,对于同一个classLoader,不管加载多少次,对应到堆内存中的class是同一个(from cache)。
所以可以使用不同的classLoader加载同名的不同类

虚拟机规范规定类的加载是通过全限定名(包名+类名)来获取二进制数据流。
调用loadClass->findClass->getClassBytes+defineClass

常见的是class二进制文件形式,但可以是以下:

  1. 运行时动态生成,如ASM ,jdk动态代理,CGLIB
  2. 网络获取
  3. 读取zip获得类的二进制字节流,如war,jar。
    war,jar使用的是和zip一样的压缩算法。
  4. 将类的二进制文件储存在数据库的BLOB字段类型中。
  5. 运行时生成class文件,并动态加载,如Thrift/AVRO可以在运行时将schema文件生成对应的class文件再加载。

3.2 类的连接阶段

验证

文件格式:确保类文件正确性。如class版本,魔数 CAFEBABE,MD5比对(class末尾)等。

元数据:确保class符合jvm规范。语义验证。

字节码:…
符号引用:…

准备

为类的静态变量 分配内存,初始化默认值。
如 static int a = 10; 在【准备阶段】a是0而不是10。
如final static int b = 10; 注意,final static变量是【被动引用】,在编译期间即直接赋予了10;
《Java高并发编程详解-多线程架构与设计》Java Classloader_第6张图片

《Java高并发编程详解-多线程架构与设计》Java Classloader_第7张图片

解析

将类中符号引用转为直接引用。
在常量池中寻找类、接口、字段、方法的符号引用,将其替换成直接引用。
《Java高并发编程详解-多线程架构与设计》Java Classloader_第8张图片

初始化

《Java高并发编程详解-多线程架构与设计》Java Classloader_第9张图片
()保证顺序,对后面的静态变量只能赋值不能访问
《Java高并发编程详解-多线程架构与设计》Java Classloader_第10张图片

类加载过程实例剖析

《Java高并发编程详解-多线程架构与设计》Java Classloader_第11张图片

发布于2019年7月14日 20:24:54

你可能感兴趣的:(Java,读书笔记)