You have to make a distinction between Loading of a Class
and Resolving a Class
.
Class literals and the special method Class.forName(…)
are different than the method ClassLoader.loadClass(…)
. While a ClassLoader
might implement the latter in strange ways, e.g. by returning different instances on each call, the JVM will resolve each class exactly once per context and remember the result.
The important point is, if the resolution of a symbolic reference could be redirected, a static final
variable would not help either. If you have two instances of the same Class
in your JVM, two different version of their static final
fields would exist as well.
There is a one-by-one mapping between a Class
instance and the JVM per class data.
To cite a few official words:
JVMSpec § 5.3.2. Loading Using a User-defined Class Loader
… First, the Java Virtual Machine determines whether L has already been recorded as an initiating loader of a class or interface denoted by N. If so, this class or interface is C, and no class creation is necessary. …
…
JVMSpec § 5.3.5. Deriving a Class from a class File Representation
The following steps are used to derive a Class object for the nonarray class or interface C denoted by N using loader L from a purported representation in class file format.
(1) First, the Java Virtual Machine determines whether it has already recorded that L is an initiating loader of a class or interface denoted by N. If so, this creation attempt is invalid and loading throws a LinkageError.
…
(5) The Java Virtual Machine marks C as having L as its defining class loader and records that L is an initiating loader of C (§5.3.4).
The important point as pointed out by § 5.3.5 is that each ClassLoader
can define at most one class per unique symbolic name. It might return different instances by delegating to different loaders but then they would be remembered as the defining loader. And the JVM will ask the defining loader when resolving references from a Class
to another Class
. Or skip asking it as § 5.3.2 states when a Class
for a given name and loader already exists.