1、类加载宏观图:
2、ClassLoader.loadClass() 关键流程:
- 加载:在磁盘上查找并通过io读入字节码文件;将字节流所代表的静态存储结构转化为方法区的运行时数据结构;在内存中生成一个代表这个类的java.lang.Class对象,作为方法去这个类的各种数据的访问入口
- 验证:1、文件格式验证:验证字节流是否符合Class文件格式的规(如:.class文件开头为CAFE BABE),并且能够被当前虚拟机处理。2、元数据验证:内容是否符合JVM规定。3、字节码验证:验证字节码文件方法中的Code结构,就是验证所编写的方法是否正确合理。(语法校验等)。4、符号引用验证:JVM将符号引用转化为直接引用的时候校验。该阶段会把一些静态方法(符号引用,比如main()替换为指向数据所存内容的指针或句柄等)也叫静态链接
- 准备:为类的静态变量分配内存并设置初始值,在这个阶段把这些变量所使用的内存在方法区进行分配
- 解析:JVM将常量池内的符号引用替换为直接引用的过程
- 初始化阶段:就是执行类构造器()方法的锅成功。常量赋值、静态代码块直径过程。(准备阶段是对常量设置初始值,这里是对常量设置我们自己定义的值)
验证、准备、解析通称为链接过程
类被加载到方法区后主要包含运行时常量池、类型信息、字段信息、方法信息、类加载器的引用(这个类到类加载器实例的引用)、对应class实例的引用等信息(类加载器在加载类信息放到方法区后,会创建一个对应的Class类型的对象实例放到堆中,作为开发人员访问方法区中类定义的入口和切入点),主类在运行过程中如果使用到其他类,会懒加载
3、类加载器:
- 引导类加载器:负责加载支持JVM运行的,位于JRE的lib目录下的核心类库,如:rt.jar等(由于引导类加载器是使用C++语言实现的,当我们调用getClassLoader时会返回NULL,属于正常现象)
- 扩展类加载器:负责加载支持JVM运行的,位于JRE的lib目录下EXT扩展目录中的JAR
- 应用程序类加载器:负责加载ClassPath路径下的类包,主要是加载我们自己应用程序的类
- 自定义类加载器:负责加载用户自定义路径下的包
优点: - 沙箱安全机制:防止一些java核心的类,如String、Long被篡改
- 避免重复的类加载:当父亲已经加载了该类时,子classLoader就没有必要再加载一次了,保证被加载类的唯一性
源码分析:
//实现自定义类加载器也非常简单
//思路:查看AppClassLoader 源码,跟着写
static class AppClassLoader extends URLClassLoader
public class URLClassLoader extends SecureClassLoader implements Closeable
public class SecureClassLoader extends ClassLoader
//通过追踪我们发现继承了 ClassLoader 这个抽象类,并重写了loadClass这个方法
public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
int var3 = var1.lastIndexOf(46);
if (var3 != -1) {
SecurityManager var4 = System.getSecurityManager();
if (var4 != null) {
var4.checkPackageAccess(var1.substring(0, var3));
}
}
if (this.ucp.knownToNotExist(var1)) {
Class var5 = this.findLoadedClass(var1);
if (var5 != null) {
if (var2) {
this.resolveClass(var5);
}
return var5;
} else {
throw new ClassNotFoundException(var1);
}
} else {
//直接看return
return super.loadClass(var1, var2);
}
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
//首先,检查该类是否已经加载
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
/*
* 核心代码:如果父类不为null,则调用分类的loadClass
* parent为属性
*/
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 如果找不到类,则抛出ClassNotFoundException
}
if (c == null) {
// 如果仍然找不到,请按顺序调用findClass 查找该类
long t1 = System.nanoTime();
c = findClass(name);
// 这是定义类加载器;记录统计数据
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}