When dynamically loading a class, when is it appropriate to use
Class.forName("SomeClass");
and when should I use
ClassLoader.getSystemClassLoader().loadClass("SomeClass");
Or, are they two ways of doing the same thing?
When dynamically loading a class, when is it appropriate to use
Class.forName("SomeClass");
and when should I use
ClassLoader.getSystemClassLoader().loadClass("SomeClass");
Or, are they two ways of doing the same thing?
They are quite different!
As stated in the documentation for Class.forName(String)
,
Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to:
Class.forName(className, true, currentLoader)
(true
here refers to do you want to initialize the class?)
On the other hand, ClassLoader.loadClass(String)
:
Invoking this method is equivalent to invoking
loadClass(name, false)
.
(here, the boolean has nothing to do with initialization; but if you check loadClass(String, boolean) documentation, you will see that all it does is load the class, not initialize it).
The first one (Class.forName("SomeClass");
) will:
The other (ClassLoader.getSystemClassLoader().loadClass("SomeClass");
) will:
Suppose you are coding a web application that will be executed on a container such as Tomcat. What Tomcat does is create a class loader for each web application (so that it can unload the webapps later and release memory -- you need a dedicated class loader for this to work!). In this situation, you can see that both calls will yield quite different results!
For more detailed (and authoritative) information on class loading and initialization, check sections 12.2 and 12.4 of the latest (3rd) edition of the Java Language Specification.
Class.forName()
uses the caller's classloader and initializes the class (runs static intitializers, etc.)
loadClass
is a ClassLoader
method, so it uses an explicitly-provided loader, and initializes the class lazily (on first use).
Note that there's a Class.forName() that also takes a ClassLoader
.
Class.forName()
load and initialize the class. In class loader subsystem it executes all the three phases i.e. load, link, and initialize phases.
ClassLoader.loadClass()
behavior, which delays initialization until the class is used for the first time. In class loader subsystem it executes only two phases i.e. load and link phases.
For example:
class MyClass {
static {
System.out.println("static block in MyClass");
}
}
public class TestCase1 {
public static void main(String... args) throws Throwable {
Class.forName("A");
}
} //The above TestCase1 produce output: static block in MyClass
public class TestCase2 {
public static void main(String... args) throws Throwable {
ClassLoader.getSystemClassLoader().loadClass("MyClass");
}
} //The above TestCase2 not produce any output
They are basically doing the same thing. The ClassLoader used may be different though. Class.forName uses the ClassLoader you get from this.getClass().getClassLoader() whereas your other code specifies to use the system class loader.
In most applications this will be the same class loader but in more complicated environments such as a J2EE app or an applet this may not be the case.
ClassLoader is an abstract class, however your application is always loaded by a classloader, there could be custom class loaders such as network classloader or any other source.
On the other hand Class in itself represents classes and interfaces and the class Class has a forName function that uses the current class loader in which your application is running by default to load the class.
Here is the source for the Class.forName which in turn invokes the calling classloader.
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName0(className, true, ClassLoader.getCallerClassLoader());
}
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#forName(java.lang.String)
Hint: Primordial class loader http://docs.oracle.com/javase/1.4.2/docs/guide/security/spec/security-spec.doc5.html
I love Class loading in java...
It really depends on what context the application is being run in. You will get different results if you are using it from a web context as opposed to just a command line program.
I've also run into problems depending on what your ClassPath looks like and what I was expecting to happen.
This JavaWorld article explains a good deal about it.