JAVA 类加载 随记
视频: https://www.bilibili.com/video/av29502877
1 JVM把Class加载到内存当中,检验解析初始化。默认使用的懒加载方式。
以下步骤是并行执行
可以把加载源看成JAVA配置文件。
解析:
符号引用: 类名,基本类型
直接引用:内存地址
初始化:
1 类初始化是线程安全的,多个线程同时触发类初始化时,只有一个类可以执行,其他类阻塞
2 类初始化时执行<clinit>方法,<clinit>按照书写顺序加载并执行类的static代码。
自上而下,由父到子。自加载器将加载任务上抛,直到顶层。父类加载器加载失败抛出异常,把加载任务转给子类加载器。
这样可以防止重复加载。比如:自定义一个java.lang.Object类,加载时先放到顶层父加载器中,发现已经加载过jdk的java.lang.Object类。此时就不会在加载自定义Object。
下面是java中类加载双亲委派的源码
java.lang.ClassLoader#loadClass(java.lang.String, boolean)
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 检查全类名是否已经加载
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) { //有父加载器
c = parent.loadClass(name, false);
} else { //无父加载器 执行启动类加载器
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) { //如果上边的加载都失败(父加载器失败)则自己尝试加载
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}