Java类的加载过程
JVM将类加载过程分为三步:装载、链接、初始化,其中链接分为三步:验证、准备、解析。
类的加载过程
-
装载load:查找并加载类的二进制数据;
-
链接link:
- 验证verify:确保被加载类的正确性;
- 准备preparation:为类的静态变量分配内存,并将其初始化为默认值;
- 解析resolution:把类的符号引用转换为直接引用
-
初始化initiation:为类的静态变量赋予正确的初始值;
类的初始化
6种情况可以导致类的初始化:
public class LoadMethod {
static {
System.out.println("LoadMethod is Load");
}
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// 1.第一次实例化类
ClassA classA = new ClassA();
// 5.反射
Class<ClassA> classAClass = (Class<ClassA>) Class.forName("com.stupidzhe.jdklearning.classloader.ClassA");
// 3.调用类中的静态变量
System.out.println(ClassA.name);
// 4.调用类中的静态方法
ClassA.print();
// 5.初始一个类的子类
ClassB classB = new ClassB();
// 6.该类被作为启动类
}
}
类的初始化步骤
1)如果这个类还没有被加载和链接,那就先进行加载和链接;
2)假如该类存在直接父类,并且父类没被初始化,那就初始化直接的父类(ps. 在一个类加载器中,类只能加载一次);
3)如果类中存在初始化语句,那就执行这些初始化语句。
类的装载
类的加载指的是将类的.class文件中二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的Class对象,用来封装类在方法区类的对象。
Class对象封装了类在方法区的数据结构(比如静态变量、常量),并且给程序员提供了访问方法区内的数据结构的接口;加载类的方式有以下几种:
- 从本地系统直接加载
- 通过网络下载.class文件
- 从归档文件中加载.class文件
- 将Java源文件动态编译为.class文件
- 从专有数据库中提取.class文件
加载器
JVM的类加载是通过ClassLoader及其子类来完成的。
- Bootstrap ClassLoader:负责加载$JAVA_HOME中jre/lib/rt.jar,是由cpp实现的;
- Extension ClassLoader:负责加载Java平台扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/ext/*.jar或-Djava.ext.dirs指定目录下的jar包;
- App ClassLoader:负责加载classpath中指定的jar包及目录中class;
- Custom ClassLoader:属于用户自定义的ClassLoader,根据j2ee规范自行实现。
JVM通过双亲委派模式模式进行类加载
为什么要用双亲委派模式?
好处是Java类随着它的加载器一起具备了一种带优先级的层次关系,通过这样层次关系可以避免类的重复加载。
ps.还有个上下文类加载器不符合双亲委派模式