Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Difference between Class.forName and ClassLoader.loadClass

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?

like image 260
IAmYourFaja Avatar asked Dec 01 '11 16:12

IAmYourFaja


People also ask

What the class forName () does?

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.

What are different types of ClassLoader?

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.

When would you use a ClassLoader?

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.

What is meant by ClassLoader in Java?

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.


4 Answers

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.

like image 104
Shaun Avatar answered Oct 19 '22 12:10

Shaun


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.

  • Initialization of the class is performed in loadClass of the ClassLoader w/ code like that: 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)

like image 26
bestsss Avatar answered Oct 19 '22 10:10

bestsss


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.

like image 3
G_H Avatar answered Oct 19 '22 11:10

G_H


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

like image 1
joe Avatar answered Oct 19 '22 10:10

joe