What is the difference between Class.forName
and ClassLoader.loadClass
in the following codes:
Class theClass = Class.forName("SomeImpl");
SomeImpl impl = (SomeImpl)theClass.newInstance();
and
Class theClass = ClassLoader.loadClass("SomeImpl");
SomeImpl impl = (SomeImpl)theClass.newInstance();
Are they synonymous? Is one preferable to the other in certain circumstances? What are the do's and dont's when using these two methods?
forName. Returns the Class object associated with the class or interface with the given string name, using the given class loader. Given the fully qualified name for a class or interface (in the same format returned by getName ) this method attempts to locate, load, and link the class or interface.
As we can see, there are three different class loaders here: application, extension, and bootstrap (displayed as null). The application class loader loads the class where the example method is contained. An application or system class loader loads our own files in the classpath.
Java uses ClassLoader implicitly when you use new , import keyword, the jvm will use the current class's classloader to load the dependent classes, so you can use the custom classloader to load a bootstrap class explicitly by using classloader.
The Java Class Loader is a part of the Java Runtime Environment that dynamically loads Java classes into the Java Virtual Machine. Usually classes are only loaded on demand. The Java run time system does not need to know about files and file systems as this is delegated to the class loader.
Class.forName() will always use the ClassLoader of the caller, whereas ClassLoader.loadClass() can specify a different ClassLoader. I believe that Class.forName initializes the loaded class as well, whereas the ClassLoader.loadClass() approach doesn't do that right away (it's not initialized until it's used for the first time).
Just found this article when looking to confirm my summary of the initialization behavior. It looks like this has most of the information you're looking for:
http://www.javaworld.com/javaworld/javaqa/2003-03/01-qa-0314-forname.html
This usage is pretty cool, though I've never used it before:
Class.forName(String, boolean, ClassLoader)
It allows you to specify a ClassLoader and the boolean parameter defines whether the class should be initialized when it's loaded or not.
Shaun's answer is more or less correct except few omissions/small errors:
Class.forName
associates the class w/ the ClassLoader (regardless if any other parent loads it for real), hence ClassLoader.findLoadedClass
is successful next time. That's a very, very important point, most ClassLoader would try Class c = findLoadedClass(name); if (c!=null) return c;
as first statements bypassing the whole find/look up part. Calling ClassLoader.load directly will not add the class to the loaded ones.The case has implications when loaded via graph alike structure of ClassLoader, i.e. not using parent only to lookup first.
if (resolve) resolveClass(c);
and the ClassLoader can actually skip resolve it it feels like, unrecommended but possible.What are the do's and dont's to using these two methods?
Unless you have very strong idea why you want ClassLoader.loadClass(String)
, do not use it directly. In all other case, always rely on Class.forName(name, true, classLoader)
.
Overall Class loading is next to an art and it cannot be covered in a simple answer (not joking about art part)
When use you use Class.forName("SomeImpl")
, you're obtaining the class via the current classloader (i.e. the loader of the class that you're making the method call in). It will also initialize the class. It's effectively the same as calling Class.forName("SomeImpl", true, currentLoader)
where currentLoader
would be the caller's classloader. See the details here.
The second method requires a classloader to be chosen first. Don't write it like ClassLoader.loadClass("SomeImpl")
since it is not a static method. You'd require something like
final ClassLoader cl = this.getClass().getClassLoader();
Class theClass = cl.loadClass("SomeImpl");
Mind that subclasses of ClassLoader should override the findClass method rather than loadClass
. This is the same as calling the (protected) method loadClass("SomeImpl", false)
, where the second argument indicates whether linking should be done or not.
There are more subtle differences... The loadClass
method expects a binary class name as specified by the Java Language Specification, while forName
could also be used with Strings representing primitive types or array classes.
Overal, it's best to use Class.forName
, if necessary specifying a specific classloader and whether it must be intialized or not, then let the implementation figure out the rest. Using classloaders directly is good for finding resources in a jar or on the classpath.
This line won't compile:
Class theClass = ClassLoader.loadClass("SomeImpl");
because loadClass is not a static method of ClassLoader.
To fix this problem, create a ClassLoader object as follows in one of 3 possible ways:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ClassLoader classLoader = Main.class.getClassLoader(); // Assuming in class Main
ClassLoader classLoader = getClass().getClassLoader(); // works in any class
then call:
Class theClass = classLoader.loadClass("SomeImpl");
-dbednar
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With