如何理解“每个Class对象都包含对定义它的ClassLoader的引用。”?

时间:2015-01-27 07:19:07

标签: java class jvm classloader

  • 我知道我可以得到一个类的类加载器 xxxclass.class.getClassLoader(),但xxxclass到底在哪里 持有定义它的类加载器的引用? 例如

    public class ClassA {    
        System.out.println("I am class A"); 
    }
    

    我在ClassA中没有看到任何关于类加载器引用的线索。然而, 我可以通过使用获得ClassA的类加载器 ClassA.class.getClassLoader()

  • ClassA.class.getClassLoader()如何运作?

4 个答案:

答案 0 :(得分:3)

ClassLoader文档中出现的句子是:

  

每个Class对象都包含一个reference到定义它的ClassLoader。

请注意这两个链接?他们告诉你的是文档引用了Class对象,而不是类ClassA的普通对象。

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

正如您所注意到的,访问Class对象的一种方法是使用ClassA.class。如果您引用了ClassA类型的对象:

ClassA myObj = new ClassA();

然后,您可以使用Class获取myObj.getClass()对象。

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

现在,另一个链接告诉您如何通过ClassLoader方法获得Class对象后getClassLoader()对象的引用。

现在,如果你查看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()来获取类加载器。它的来源是:

native ClassLoader getClassLoader0();

也就是说,类加载器引用实际上是此Java类的本机结构的一部分,并且无法使用Java语言工具。然而,它存在于那里,并可通过上述方法获得。

答案 1 :(得分:1)

如果你这样写:

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

    public Person getThrower() {return thrower;}
}

然后每个Ball对象都包含对投放它的Person的引用,对吗?

同样,Class类也有类似内容:(虽然我没有说明如何分配classLoader

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

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

    ... other stuff ...
}

所以每个Class对象都引用了加载它的ClassLoader

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

答案 2 :(得分:1)

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

(或至少, 并非如此简单,直到最近的更新)

Java是一种非常高级的语言,JVM是一个相当复杂的野兽,幸运的是,它隐藏了许多你不想在使用高级,面向对象时需要关注的细节。语言。

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

但是由于开源JDK,人们可以跟踪这个方法调用的路径(这里是最新版本的JDK8):


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

答案 3 :(得分:0)

如果查看java.lang.Class的源代码,它似乎委托给一个名为getClassLoader0的本机方法。因此,实现细节归结为JVM。

我不是这方面的专家,但我想这可能会让垃圾收集工作,因为没有Java中的参考周期。