Featured image of post 类加载器

类加载器

类加载器

menu

🙈 BootstrapClassLoader

启动类加载器,最顶层的加载类,由 C/C++ 实现。

负责加载:

  • %JAVA_HOME%/lib 目录下的 jar 包和类
  • -Xbootclasspath 参数指定的路径中的所有类。

🙉 ExtensionClassLoader

扩展类加载器。

是一种 Java 系统类库的扩展机制。负责加载 %JRE_HOME%/lib/ext 目录下的 jar 包和类,或被 java.ext.dirs 系统变量所指定的路径下的 jar 包。

🙊 ApplicationClassLoader

面向用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。

双亲委派模型

classloader

每个类加载器都有自己的命名空间,用不同的类加载器加载了同一个限定名的类,JVM 也会认为是两个不同的类。

 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
34
35
36
37
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // (1) 判断是否加载过该类
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        // (2) parent == null 约定为:parnet 为 Bootstracp ClassLoader
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // (3) 说明 parent 加载不了,当前 loader 尝试加载 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;
        }
    }

默认情况下,一个限定名的类只会被一个类加载器加载并解析使用,在程序中是唯一的,不会产生歧义。

在加载时,首先会判断当前类是否被加载过,如果已经加载,会直接返回,否则才会尝试加载。

尝试加载时,不会自己进行加载,而是将请求委派给父类加载器,当父类加载器无法加载时,才会由自己处理。