这是我参与「第四届青训营 」笔记创作活动的第2天
最近做安卓青训营的项目,对如此多的api给震惊到了,好奇java中类加载的机制到底是如何把海量的方法和类找到的。
一、概念
把描述类的数据从 Class 文件加载到内存
该过程包括了
- 加载
- 链接
- 初始化
1. 加载
类加载器(ClassLoader) 把class读入内存创建Class对象
2. 链接
把数据加载到JRE,给数据赋值
主要包括了
- 验证 --- 验证.class文件字节流是否符合class文件的格式的规范,验证class文件的魔术版本等
- 准备 --- 对Static变量设置默认值(不是初始值!!)
- 解析 --- 将类的二进制数据中的符号引用替换成直接引用
3. 初始化
- 初始化static(把准备阶段的static变量改成初始值)
- 假如这个类还没有被加载和连接,则程序先加载并连接该类
- 假如该类的直接父类还没有被初始化,则先初始化其直接父类
- 假如类中有初始化语句,则系统依次执行这些初始化语句
二、类加载的时机
- 初始化一个类时发现父类未加载
- new或反射调用的时候
- 调用静态方法或静态变量
三、3个类加载器ClassLoader
1. 启动类加载器
负责加载java核心类库(String等)
2. 扩展类加载器
加载jre中的jar
3. 应用程序类加载器
加载CLASSPATH路径下我们自己写的类
注意:getParent()获取到的父加载器!=父类
关键代码在Launcher.class下
四、类加载机制(双亲委派)
简述:属实是老生常谈了
三个步骤
- 查询缓存(已加载过则返回)
- 未加载过则请求父类去加载
- 父类加载失败则递归回来该类加载器查看是否能加载
好处:
优先使用父加载器,防止自己写个String去替换jdk的String类
例子: 看看ClassLoader下的loadClass方法,这个方法在子类多有重写
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
//这里底层是调用了c++的搜索类,其实就是搜索缓存
Class<?> c = findLoadedClass(name);
if (c == null) {
if (parent != null) {
// 父加载器去加载
c = parent.loadClass(name, false);
} else {
// bootstrapclassloader是用c++写的无法使用getParent获取到
c = findBootstrapClassOrNull(name);
}
}
if (c == null) {
// 父类和缓存都没有加载,要自己去尝试加载了
c = findClass(name);
}
}
return c;
}
}
五、自定义类加载器
既然loadclass帮我们处理了双亲委派机制,我们自定义类只需要重写findclass方法,这个方法主要就是使用io读取目的的类
具体要怎么使用,使自己的容器具有特性,可以参考tomcat的类加载实现,防止了new出一个tomcat容器 具体可以拜读cloud.tencent.com/developer/a…