类的阶段
在Java代码中,类型的加载、连接和初始化都是在程序运行期完成的。类有以下几个阶段:
- 类加载:即查找并加载类的二进制数据
- 类连接:
- 验证:确保被加载类的正确性
- 准备:为类的静态变量分配内存,并将其初始化为默认值
- 解析:类的符号引用转换为直接引用
- 类初始化:为类的静态变量赋予正确的初始值,运行static快中的代码。
- 类使用
- 类卸载
类加载
类加载:类的加载是指将类的.class文件的二进制数据读入内存中,将其放在运行时数据区的方法区中,然后在内存中创建了一个java.lang.Class对象(HotSpot中这个Class对象在方法区)用来封装类在方法区的数据结构。(比如反射就是用的Class对象)
加载.class文件的方式
- 从本地系统磁盘直接加载(classpath下的文件)
- 通过网络下载.class文件
- 通过zip、jar等归档文件加载.class文件(多用于第三方的jar包)
- 将java源文件动态编译成.class文件(比如动态代理,运行期生成代理类的类加载过程)
类的初始化
java程序对类的使用方式有两种:
- 主动使用
- 被动使用
类初始化的时机
所有的jvm实现都必须保证在每个类或接口都被程序“首次主动使用”时才进行初始化。(这里是类初始化)
使用类
主动使用类有下面几种方式:
- 创建类的实例
- 访问类或者接口的静态变量,或者对这个静态变量进行赋值。
- 调用类的静态方法
- 反射加载一个类
- 初始化一个类的子类,则父类也算被主动调用。
- 启动类,比如test
- 动态语言支持,
java.lang.invoke.MethodHandle
实例的解析结果的句柄对应类没有初始化,则进行初始化
被动使用:除了主动使用类的方式使用类或接口,都会被看做是类的被动使用,不会导致类的初始化。
一个例子解释类的主动使用和被动使用
1 | public class TestClassLoading { |
对应的输出:
1 | Parent初始化。。。。 |