43

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?

Usama Abdulrehman
  • 1,041
  • 3
  • 11
  • 21
IAmYourFaja
  • 55,468
  • 181
  • 466
  • 756
  • Personally I try not to use literal strings in my code... Consider writing `SomeImpl.class.getSimpleName()` instead of the hard-coded literal (saves headaches when renaming the class). – Yuval Dec 01 '11 at 17:33
  • 8
    @Yuval: Ordinarily I'd agree with you, but in the case of `Class.forName()` the *whole point* is that you pass it a string. If you have a `Class` instance lying around, then you don't need to call `Class.forName()`. And if you can write `SomeImpl.class` then you can write `new SomeImpl()` instead of using reflection at all. – Daniel Pryden Dec 01 '11 at 19:40
  • 2
    @Yuval, dynamic class loading is a core feature in Java and has nothing to do w/ use of string instead of class. [D. Pryden covers that already] – bestsss Dec 01 '11 at 19:53
  • The class type can be passed as an argument to the code (a `Class>` parameter) for this purpose, but generally you're right. – Yuval Dec 03 '11 at 17:17
  • possible duplicate of [Class.forName() vs ClassLoader.loadClass() - which to use for dynamic loading?](http://stackoverflow.com/questions/8100376/class-forname-vs-classloader-loadclass-which-to-use-for-dynamic-loading) – mechanical_meat Mar 29 '12 at 21:48

5 Answers5

20

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
  • 2,446
  • 19
  • 33
  • 2
    It will only use the caller's classloader if you don't provide one. From the same article: "...If picking a specific loader to load the class is important to your design, you should use `ClassLoader.loadClass()` **or the three-parameter version of forName()** added in Java 2 Platform, Standard Edition (J2SE): `Class.forName(String, boolean, ClassLoader)`." – phs Jul 22 '13 at 23:43
11

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)

bestsss
  • 11,796
  • 3
  • 53
  • 63
3

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.

G_H
  • 11,739
  • 3
  • 38
  • 82
1

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

joe
  • 329
  • 3
  • 4
0

The loadClass() method can't be called as a static one. Create sub class for ClassLoader and have some additional other methods to do operations. Can create your own class loader by extendingClassLoader class. In functional both ways are same.

Vladimir Vagaytsev
  • 2,871
  • 9
  • 33
  • 36
Hari
  • 1
  • 1