类加载机制
类加载时机
- 类的初始化时机:只有对类的主动使用才会导致类的初始化
- Java虚拟机启动时被标明为启动类的类,虚拟机会先初始化这个主类。
- 遇到 new、getstatic、putstatic(被static final同时修饰、已在编译器把结果放入常量池的静态字段除外)、invokestatic(调用静态方法) 这四条字节码指令
- 调用反射时,java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法
- 初始化一个类时,如果父类未初始化,则触发父类的初始化
- 被动引用不会初始化
- 子类调用父类静态字段,静态方法,子类不会初始化
- 定义对象数组
- final修饰的静态常量
类的加载过程
总体类加载原则
- 所有静态变量 > 其他
- 父类 > 子类
- 成员变量 > 构造函数,并且两个操作要原子完成
使用
卸载
类加载器
双亲委派模型
如果一个类加载器收到了类加载请求,它不会直接处理,而是委派给父类加载器去完成,直到找到最顶层
- 保证了类的统一性,如果用户自定义了一个Object,也会使用顶层类加载器
破坏双亲委派机制
重写java.lang.ClassLoader中的findClass()方法
public class myClassLoader extexnd ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = loadByte(name);
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
}
// 使用类加载器
myClassLoader.loadClass("com.ha.Car");
类加载器类型
- 引导类加载器(Bootstrap ClassLoader):最顶层的加载类,主要加载核心类库
- 扩展类加载器(Extensions ClassLoader):
- 系统类加载器(System ClassLoader):加载当前项目下的类
- 自定义类加载器
Class.forName()和ClassLoader.loadClass()区别
- Class.forName():将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块;
- ClassLoader.loadClass():只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。