如何理解"Every Class object contains a reference to the ClassLoader that defined it. "?

How to understand "Every Class object contains a reference to the ClassLoader that defined it. "?

如果您查看 java.lang.Class 的源代码,您会发现它委托给了一个名为 getClassLoader0 的本机方法。因此,实现细节取决于 JVM。

我不是这方面的专家,但我想这可能允许垃圾收集通过在 Java 中没有引用循环来工作。

如果这样写:

public class Ball {
    private Person thrower;
    public Ball(Person thrower) {
        this.thrower = thrower;
    }

    public Person getThrower() {return thrower;}
}

那么每个 Ball 对象都包含对抛出它的 Person 的引用,对吗?

类似地,Class class 有这样的东西:(尽管我没有展示 classLoader 是如何分配的)

public class Class {
    ... other stuff ...

    private ClassLoader classLoader;
    public ClassLoader getClassLoader() {return classLoader;}

    ... other stuff ...
}

因此每个 Class 对象都有一个对加载它的 ClassLoader 的引用。

在您的示例中,ClassA 不是 Class 对象,因此该语句不适用于它。它适用于ClassA.class一个Class对象(或至少指一个对象)。

出现在 ClassLoader 文档中的句子是:

Every Class object contains a reference to the ClassLoader that defined it.

注意到两个 link 了吗?他们告诉你的是文档指的是 Class 对象,而不是 class ClassA.

的普通对象

您在 Java 中定义的每个 class 都有一个与之关联的 Class 对象,这使您可以在元级别中查看该 class。也就是说,将 class 本身视为一个对象,将其作为参数传递,对其使用反射等

如您所见,访问 Class 对象的一种方法是使用 ClassA.class。如果您引用了 ClassA:

类型的对象
ClassA myObj = new ClassA();

然后你可以使用myObj.getClass()获得Class对象。

因此 myObj 对象中没有对 ClassLoader 的引用,仅在其关联的 Class 对象中。

现在,另一个 link 告诉您如何在拥有 Class 对象后获取对 ClassLoader 对象的引用 - 通过 getClassLoader() 方法。

现在,如果您查看 Class class 的源代码,您将看到:

@CallerSensitive
public ClassLoader getClassLoader() {
    ClassLoader cl = getClassLoader0();
    if (cl == null)
        return null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
    }
    return cl;
}

所以它调用 getClassLoader0() 来获取 class 加载程序。它的来源是:

native ClassLoader getClassLoader0();

即class加载器引用实际上是这个Javaclass的原生结构的一部分,使用Java语言是看不到的工具。然而,它存在于那里,并且可以通过上述方法使用。

事实上,在这种情况下并没有那么简单。

(或者至少,它 没那么简单,直到最近的更新)

Java 是一种非常高级的语言,而 JVM 是相当复杂的野兽,它(幸运的是!)隐藏了许多您在使用高级语言时不想关心的细节级,面向对象的语言。

正如其他答案中已经指出的那样,Class#getClassLoader() 方法委托给 private native 方法 getClassLoader0()。通常,您根本不知道(也不应该关心)私有 native 方法的作用。

但感谢开源 JDK,可以追踪此方法调用的路径(这里,对于 JDK8 的最新版本):


但是,请注意 this has changed in a recent commit of the JDK9:现在,ClassLoader 作为私有实例字段存储在 Class class 中,以提高性能。