Is this equivalent to
class A {
// ...
A.class.getClassLoader().loadClass("B's canonical name").newInstance();
// ...
}
?
No, not always.
Class loading is performed only once for a given namespace, unless the Class
in question has been previously unloaded. Therefore, the equivalent expression A.class.getClassLoader().loadClass("B's canonical name")
will be executed only once in most scenarios. In other words, if you have two expressions - new A()
, the loadClass
will be performed only once.
Invocation of a constructor is treated as a method invocation by the JVM, but this requires the cooperation of a Java compiler. The JVM and the compiler have to adhere to section 3.9 of the Java Virtual Machine Specification, which states:
3.9 Specially Named Initialization Methods
At the level of the Java virtual machine, every constructor (§2.12)
appears as an instance initialization method that has the special name
<init>
. This name is supplied by a compiler. Because the name <init>
is not a valid identifier, it cannot be used directly in a program
written in the Java programming language. Instance initialization
methods may be invoked only within the Java virtual machine by the
invokespecial instruction, and they may be invoked only on
uninitialized class instances. An instance initialization method takes
on the access permissions (§2.7.4) of the constructor from which it
was derived.
A class or interface has at most one class or interface initialization
method and is initialized (§2.17.4) by invoking that method. The
initialization method of a class or interface is static and takes no
arguments. It has the special name <clinit>
. This name is supplied by
a compiler. Because the name <clinit>
is not a valid identifier, it
cannot be used directly in a program written in the Java programming
language. Class and interface initialization methods are invoked
implicitly by the Java virtual machine; they are never invoked
directly from any Java virtual machine instruction, but are invoked
only indirectly as part of the class initialization process.
This section assumes that the Class
object pertaining to the class in question is available to the current thread. Once the Class
object is available, the method <init>
corresponding to the constructor with the right set of arguments, will be invoked.
The question of which classloader will be used to load the class, if not already loaded, is a bit different, and has nothing to do with the new keyword. It depends on how one class references another i.e. does a symbolic reference need to be resolved in the runtime constant pool? The behavior in this context is defined in Section 5.3 of the Java Virtual Machine Specification:
5.3 Creation and Loading
Creation of a class or interface C denoted by the name N consists of
the construction in the method area of the Java virtual machine
(§3.5.4) of an implementation-specific internal representation of C.
Class or interface creation is triggered by another class or interface
D, which references C through its runtime constant pool.
...
The Java virtual machine uses one of three procedures to create class
or interface C denoted by N:
If N denotes a nonarray class or an interface, one of the two following methods is used to load and thereby create C :
If D was defined by the bootstrap class loader, then the bootstrap
class loader initiates loading of C (§5.3.1).
If D was defined by a user-defined class loader, then that same
user-defined class loader initiates loading of C (§5.3.2).
Otherwise N denotes an array class. An array class is created directly by the Java virtual machine (§5.3.3), not by a class loader.
However, the defining class loader of D is used in the process of
creating array class C.
Note the sentence - If D was defined by a user-defined class loader, then that same user-defined class loader initiates loading of C
in the above quote. In the context of the expression new A()
, the classloader that loaded the enclosing class will be responsible for loading A
in accordance with the VM Spec; this is of course, assuming that the enclosing class is not loaded by the bootstrap classloader.