Java 类加载

Java 类加载

类编译

.class 文件包含哪些信息 ?

类加载的过程

参考:《深入理解 Java 虚拟机》

JVM 把 Class 文件加载到内存,然后进行校验、准备、解析、初始化,最终形成可以使用的 Java 类型,这就是类加载机制。其中,校验、准备、解析这三个阶段,放在一起是链接阶段

  • 【加载】二进制字节流可以从 JAR、WAR、网络、运行时动态生成(动态代理)、JSP生成。
  • 【验证】文件格式、元数据(信息语义)、字节码验证(类型转换是否有效、跳转指令不会跳到方法体以外的地方去)、符号引用验证
  • 【准备】static final 变量赋值、各个基本数据类型的默认值
  • 【解析】常量池内的符号引用(用符号描述引用目标)替换为直接引用(直接指向目标的指针)
  • 【初始化】编译器收集 static 块、类变量的赋值放到 () 方法中

加载器类型

  • Bootstrap ClassLoader:加载 JAVA_HOME/lib、或者 -Xbootclasspath,并且是按照名字识别的,如 rt.jar
  • Extension ClassLoaderJAVA_HOME/lib/ext、或者 java.ext.dirs 系统变量
  • Application ClassLoader:加载用户 ClassPath 上的类库

类加载器之间的层次关系,称之为双亲委派模型。如果一个类收到类加载请求,那么会首先委派给父类,父类反馈无法完成,自己才进行加载。

何时初始化

  • 遇到 newgetstaticputstaticinvokestatic 这 4 条字节码指令。对应的是 new 一个对象、读取静态字段、设置静态字段(字段没有被 final 修饰,否则在编译器就已经将结果放在常量池了)、调用一个类的静态方法。
  • java.lang.reflect 进行反射。
  • 初始化 A 类,其父类没有被初始化。
  • 虚拟机启动时,包含 main() 方法的这个类
// 不会导致子类初始化
println(SubClass.parentStaticValue);

// 不会初始化 SuperClass
SuperClass[] sca = new SuperClass[10];

// 不会导致 ConstClass 初始化
println(ConstClass.staticFinalValue);

静态变量何时加载

  • static final: 编译器优化这种常量,然后将这个值直接内嵌到 bytecode 里面
  • static: 随着这个类的加载而加载