W.Zhe
W.Zhe

Reputation: 117

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

Upvotes: 0

Views: 574

Answers (4)

Marco13
Marco13

Reputation: 54611

In fact, it's not so simple in this case.

(Or at least, it was not so simple, until a recent update)

Java is a very high-level language, and the JVM is a rather complex beast, which is (fortunately!) hiding many details that you don't want to be concerned with when using a high-level, object-oriented language.

As already pointed out in the other answers, the Class#getClassLoader() method delegates to a private native method getClassLoader0(). Usually, you simply don't know (and should not have to care about) what a private native method does.

But thanks to the open source JDK, one can trace the path of this method call (here, for a recent version of the JDK8) :


However, note that this has changed in a recent commit of the JDK9: Now, the ClassLoader is stored as a private instance field in the Class class, in order to improve performance.

Upvotes: 1

RealSkeptic
RealSkeptic

Reputation: 34618

The sentence as it appears in the documentation of ClassLoader is:

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

Note the two links? What they tell you is that the documentation refers to the Class object, not to the plain object of class ClassA.

Every class that you define in Java has a Class object associated with it, which allows you to look at that class in the meta level. That is, treat the class itself as an object, pass it as parameter, use reflection on it etc.

As you have noticed, one way to access the Class object is use ClassA.class. If you have a reference to an object of type ClassA:

ClassA myObj = new ClassA();

Then you can get the Class object using myObj.getClass().

So there is no reference to the ClassLoader in the myObj object, Only in its associated Class object.

Now, the other link tells you how to get the reference to the ClassLoader object once you have a Class object - through the getClassLoader() method.

Now, if you look at the source code of the Class class, you will see:

@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;
}

So it calls getClassLoader0() to get the class loader. Its source is:

native ClassLoader getClassLoader0();

That is, the class loader reference is actually part of the native structure of this Java class, and it is not available to see using Java language tools. Nevertheless, it exists there, and available to you through the aforesaid method.

Upvotes: 3

If you write this:

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

    public Person getThrower() {return thrower;}
}

then every Ball object contains a reference to the Person that threw it, right?

Similarly, the Class class has something like this: (although I'm not showing how classLoader gets assigned)

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

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

    ... other stuff ...
}

and so every Class object has a reference to the ClassLoader that loaded it.

In your example, ClassA is not a Class object, so the statement doesn't apply to it. It does apply to ClassA.class which is a Class object (or refers to one at least).

Upvotes: 1

Stephen Souness
Stephen Souness

Reputation: 272

If you look at the source code of java.lang.Class it appears that it delegates to a native method called getClassLoader0. So the implementation details are down to the JVM.

I'm no expert on this, but I suppose this might allow garbage collection to work by not having reference cycles in Java.

Upvotes: 0

Related Questions