-36

Below is the program:

package annotationtype;

public class Example {

    public static void main(String[] args){

    }
}

got compiled with below byte code.

Classfile /D:/git/Java_programming/JavaCode/bin/annotationtype/Example.class
  ......
  Compiled from "Example.java"
public class annotationtype.Example
  .......
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // annotationtype/Example
   #2 = Utf8               annotationtype/Example
   #3 = Class              #4             // java/lang/Object
   ......
  #18 = Utf8               SourceFile
  #19 = Utf8               Example.java
{
  public annotationtype.Example();
  ........
  public static void main(java.lang.String[]);
  ......
}
SourceFile: "Example.java"

Using eclipse editor, In main() method, if I type,

Example., eclipse editor immediately provides class member of type Class<annotationtype.Example>

My understanding is,

below byte code,

#1 = Class              #2             // annotationtype/Example
 ..
#3 = Class              #4             // java/lang/Object

indicates creation of object of type Class<annotationtype.Example> pointed by member Class<annotationtype.Example> class during initialisation phase of class Example, something functionally equivalent to:

public class annotationtype.Example{
    public static Class<annotationtype.Example> class;
    {
        class = Class.forName("annotationtype.Example")
    }
    ......
}

Is my understanding correct about,

the phase at which object(creation) of type Class<annotationtype.Example> comes into existence, that is pointed by Example.class?

overexchange
  • 15,768
  • 30
  • 152
  • 347

1 Answers1

11

You are confusing artifacts of the Java programming language with items of the constant pool of a class file holding Java byte code.

Class literals of the form type.class, as well as an access to the length of an array of the form array.length may look like a member access in the source code but have nothing to do with real class members.

E.g. when you write array.length, it will get compiled to a bytecode instruction arraylength dedicated to retrieve the length of an array at runtime without actually specifying how a JVM remembers lengths of arrays. That’s implementation dependent.

A class literal is more complicated. E.g. when you write int.class, there is nothing to query. Instead, the compiler knows that it has to read the static field Integer.TYPE to get the runtime value and that’s how this class literal gets compiled, as a field access to Integer.TYPE. In contrast, class literals of reference types are compiled using an ldc instruction pointing to a constant pool entry which has nothing to to with fields.

The constant pool of a class does not contain Java objects in the first place. It contains linkage information. Some entries might get associated with a Java runtime instance on their first use but the way it works is intentionally unspecified. That’s up to the JVM. These entries serve different purposes, i.e. a Class entry can be used to specify a super class, an implemented interface or a class, whose member is accessed by a method invocation or field access.

That’s why your Example class file contains such a Class entry. It’s there because the class uses it to describe itself. Even if there is no class literal Example.class at all. Consequently, a Class instance describing the class Example is create when the class is loaded. A ClassLoader remembers all loaded classes and they will be used when the same name is resolved using the same loader.

Note that when another class contains a class literal of the form Example.class, it will have it’s own Class entry for that class within its own constant pool. The runtime evaluation of the class literal may trigger the loading and hence creating of the Class instance when it has not been loaded before. Otherwise, it gets resolved to the already loaded class via the class loader.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • For primitive types, a name would work. But reference types consist of a name *and* an initiating class loader at runtime. As said in my answer, a class loader remembers all classes defined on it and will resolve the same name to the same `Class` instance, but a different class loader might define a different runtime class with the same name. So a name can be ambiguous. In other words, there is no problem passing the result of `Class.forName` to `getConstructor` if your source is a `String`. But calling `Class.getName()` and resolving it in a different context may produce a different class. – Holger Jul 06 '15 at 12:47
  • @Holger I did not get this statement: "a class loader remembers all classes defined on it and will resolve the same name to the same Class instance, but a different class loader might define a different runtime class with the same name. So a name can be ambiguous.", *different runtime class with same name*? – overexchange Jul 07 '15 at 13:47
  • Yes, at runtime, there can be more than one class with the same name. That depends on the `ClassLoader`s. Compare [JVMS §5.3](http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.3): “*At run time, a class or interface is determined not by its name alone, but by a pair: its binary name (§4.2.1) and its defining class loader.*” See also [JLS §12.2](http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.2) – Holger Jul 07 '15 at 14:18
  • Don’t assume that the two classes named `X` are the same, just because they have the same name. They *might* be derived from the same class file, but it’s also possible, that they are different versions of an evolved class or they are simply unrelated. Frameworks like OSGi may load non-exported types multiple times in different loaders to ensure that the bundles are decoupled. Further, unloading a bundle in order to load a newer version, works exactly that way, there are tons of dynamic frameworks doing this. As long as the old loader hasn’t garbage collected, both versions exist at runtime. – Holger Jul 09 '15 at 08:48