0%

Java 类加载机制(二):理解 ClassLoader

1. 怎样理解 ClassLoader

  • ClassLoader 是一个抽象类

    • Bootstrap ClassLoader:是 JVM 实现的一部分,不是 Java 语言实现的,一般是 C++ 实现的,没有对应的具体的类
    • Extension ClassLoader:的具体实现类sun.misc.Launcher$ExtClassLoader
    • Application ClassLoader:的具体实现类sun.misc.Launcher$AppClassLoader
  • 每个 Class 对象都有一个方法,可以获取实际加载它的 ClassLoader,方法是:public ClassLoader getClassLoader()

  • ClassLoader 有一个方法,可以获取它的父 ClassLoader,方法是:public final ClassLoader getParent()。如果 ClassLoaderBootstrap ClassLoader,返回值为 null

  • ClassLoader 有一个静态方法,可以获取默认的系统类加载器,方法是:public static ClassLoader getSystemClassLoader()

  • ClassLoader 中有一个主要方法,用于加载类,方法是:public Class<?> loadClass(String name) throws ClassNotFoundException

  • 由于双亲委派机制,ClassgetClassLoader() 方法返回的不一定是 loadClass()ClassLoader

2. Class 的两个静态方法 forName() 的区别

  • public static Class<?> forName(String name)使用系统类加载器加载
  • public static Class<?> forName(String name, boolean initialize, ClassLoader loader)指定 ClassLoader,参数 initialize 表示加载后是否执行类的初始化代码(如 static 语句块),没有指定默认为 true

3. ClassLoaderloadClass() 方法与 ClassforName() 方法都可以加载类,它们的区别是

  • 基本是一样的
  • 不过,ClassLoaderloadClass() 方法不会执行类的初始化代码

4. 试分析 ClassLoaderloadClass() 方法源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false); //调用了另一个 loadClass 方法
}

//省略了一些代码
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized(getClassLoadingLock(name)) {
//首先,检测类是否已经被加载了
Class c = findLoadedClass(name);
if(c == null) {
//没被加载,先委派父 ClassLoader 或 Bootstrap ClassLoader 去加载
try {
if(parent != null) {
//委派父 ClassLoader,resolve 参数固定为 false
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch(ClassNotFoundException e) {
//没找到,捕获异常,以便尝试自己加载
}
if(c == null) {
//自己去加载,findClass() 才是当前 ClassLoader 的真正加载方法
c = findClass(name); //findClass() 是一个 protected 方法,类 ClassLoader 的默认实现就是抛出 ClassNotFoundException,子类应该重写该方法
}
}
if(resolve) { //参数 resolve 类似 Class.forName() 中的参数 initialize
//链接,执行 static 语句块
resolveClass(c);
}
return c;
}
}
-------------------- 本文结束感谢您的阅读 --------------------