JVM把class文件加入到内存中,在程序运行的时候才能使用该类,class文件从加载到调用,经历三个阶段:类加载、类连接、类初始化。
类加载:JVM把class文件加载到内存中,为之创建java.lang.Class对象,并返回。
类连接:检查加载的类是否正确,为类变量设置默认初始值,将类的符号引用变成直接引用。
类初始化:检查类是否被正确加载,先初始化父类再初始化当前类,根据初始化语句初始化类变量。
class文件的来源
1.加载本地文件系统中的class文件,包括jar包中的class文件和动态编译生成的class文件。
2.通过网络传输class文件并加载
类加载器包括根类加载器、扩展类加载器、系统类加载器、自定义类加载器。
系统类加载器实例.getParent()是扩展类加载器实例,
扩展类加载器实例的父加载器是根类加载器实例,
但是扩展类加载器实例.getParent()不是根类加载器实例,而是null,因为系统类加载器和扩展类加载器都继承类ClassLoader,根类加载器并不是ClassLoader的子类。注意类加载器之间并没有实际的继承关系。
类加载器加载class文件步骤
1.检测当前类是否加载过,如该类已经加载到内存中直接返回java.lang.Class对象
2.如果没有加载过,先使用根类加载器加载(/jre/lib/*.class),加载不成功使用父类加载器加载(/jre/lib/ext/*.class),还是加载不成功使用系统类加载器(classpath:*.class)把class文件加载到内存中
3.加载成功,创建java.lang.Class对象并返回
4.加载不成功,抛出ClassNotFoundException( )异常
类初始化时机
1.访问类成员,包括直接访问或通过反射的方式访问
2.创建类对象,包括new一个对象或者发射的方式动态创建类对象
3.初始化某类的子类时,该类也会被初始化
4.通过Class.forName(String name)强制初始化类
5.运行该类时,先初始化该类
类加载器ClassLoader源码
Class<?> loadClass(String name)加载该类
先调用findClass(String name)判断该类是否加载过,如果没有加载过该类,把class文件加入内存,并创建一个java.lang.Class对象;如果加载过该类直接把findClass方法获取的Class对象return。
Class<?> findClass(String name)在内存中查找该类
用来判断是否加载过某类,加载过则返回该Class对象,否则返回null。该方法也是自定义加载器重写的方法。
ClassLoader getParent()获取父加载器
扩展类加载器和根类加载器的父加载器都是根类加载器,因为根类加载器不是ClassLoader的子类,所以getParent()返回null。
static ClassLoader getSystemClassLoader()获取系统类加载器实例
作者:蜗先生
链接:https://www.jianshu.com/p/4791d42bb1b2