类加载器
负责将.class文件加载到内存中,并为之生成对应的Class对象
当程序使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来对其初始化
加载:指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象
连接:
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 将类的二进制数据中的符号引用替换为直接引用
初始化:我们以前讲过的初始化步骤
ClassLoader
BootClassLoader
BaseDexClassLoader
PathClassLoader
DexClassLoader
加载机制
全盘负责
当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非指定使用另外一个类加载器来载入
父类委托
先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
缓存机制
保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效
加载时机
创建类的实例
访问类的静态变量,或者为静态变量赋值
调用类的静态方法
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
直接使用java.exe命令来运行某个主类
加载方式
命令行启动应用时候由JVM初始化加载
通过Class.forName()方法动态加载
通过ClassLoader.loadClass()方法动态加载
//需优化
ClassLoader loader = HelloWorld.class.getClassLoader();
Class clazz = HelloWorld.class;
//使用ClassLoader.loadClass()来加载类,不会执行初始化块
loader.loadClass("mthodName");
//使用Class.forName()来加载类,默认会执行初始化块
clazz.forName("mthodName");
//使用Class.forName()来加载类,并指定ClassLoader,初始化时不执行静态块
clazz.forName("mthodName", false, loader);
分类
Bootstrap ClassLoader 根(启动)类加载器
也被称为引导类加载器,负责Java核心类的加载
比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载
在JDK中JRE的lib目录下ext目录
Sysetm ClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
双亲委派模型
工作流程:如果一个类加载器收到了类加载的请求,先把请求委托给父加载器去完成,依次向上。因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类
意义:系统类防止内存中出现多份同样的字节码,保证java程序安全稳定运行
ClassLoader源码
public Class<?> loadClass(String name)throws ClassNotFoundException {
return loadClass(name, false);
}
protected synchronized Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException {
// 首先判断该类型是否已经被加载
Class c = findLoadedClass(name);
if (c == null) {
//如果没有被加载,就委托给父类加载或者委派给启动类加载器加载
try {
if (parent != null) {
//如果存在父类加载器,就委派给父类加载器加载
c = parent.loadClass(name, false);
} else {
//如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方法native Class findBootstrapClass(String name)
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// 如果父类加载器和启动类加载器都不能完成加载任务,才调用自身的加载功能
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
自定义加载器
应用场景
1、执行非置信代码前,自动验证数字签名
2、动态创建定制化构建类
3、从特定场所中取得java class,如数据库和网络