Uses of classForName
Before I leap into explaining to use Class.forName, I want to give you an idea of what it is
for:
- You want write a program such as the Holiday calculator which comes with
modules for computing a few dozen Holidays. You want to make it possible for users of the program to easily add more
holiday calculator plug-ins for obscure holidays without having to look at, modify or recompile any source code.
When you want code to work with a class that does not yet exist, or is not available, at the time of compilation, you
define an interface. The base code references only that interface. You tell your clients that any new code must
implement that interface. Then at runtime you use Class. forName
to load the new class, then use its methods via the interface methods. The Holiday
calculator works this way. You can plug in you own code for new holidays without recompiling. Other places you see
this provider/plugin approach are JDBC drivers and JCE providers.
- You want to write a program that composes Java programs, compiles them, then executes them, on the fly, without human
intervention. It might generate thousands of such little programs. You need to be able to execute class files that did
not exist when your calling code was written.
- You want to write a program that generates JVM byte codes, class file images in RAM, then executes them, without ever
writing the *.class file to disk. For this you also need to write a custom ClassLoader
since the standard one does not look in RAM, only on disk in the classpath.
- You want to write a BeanBox editor that can take any Bean-compliant class and execute it and edit its fields. For this
you also need Reflection to find out what get/set methods are available.
- You want to write a spreadsheet amanuensis, a simple, flexible,
high performance spreadsheet component.
Under the Hood
Now let’s look under the hood to understand how the various tools work. There are Class
objects (objects of class Class) that represent classes (including arrays), interfaces, and
primitives. The Class.newInstance method lets you create new objects of that class without
requiring a variable declared specifically of that class. You are using the default public no arg constructor. Your
class had better have one. This allows code to be much more open ended than in other languages, with new variants added
dynamically. The Class.getName method lets you display the class name. There are also methods
to discover the details of the fields and methods associated with the class in the java.lang.reflect.*
package.
Class.forName eagerly loads the class if it not already loaded.
Inside the JVM there is a HashMap of all the classes that have been previously loaded. So Class.
forName takes under a millisecond if the class you have want is already loaded, If not, it
might take 15 milliseconds or so to load it. You pay this time penalty only the first time you use the class. Class.
forName is still slower than hard coding the name of the class into your code. With hard
coding, you avoid repeated HashMap lookups.
Creating Class Objects
You can’t instantiate Class objects, but most the Class
methods are instance methods, not static. So how do you get a Class object:
classForName is oblivious to any import statements, so you must fully qualify your class
names.
The .class syntax is a kludge, especially double.class. It
behaves as though it were a read-only static field even though there is no such field,
though obviously there must a hidden pointer in the Class object to the class name.
Class Instance Methods
You can then use methods like Class.toString, Class.getName, Class.getLoader
and Class.getSuperclass to tell you even more about the class.
Once you have the class, you can then play games with java.lang.reflect.*. Given just the
class object, you can find out the constructors, methods, parameters to those methods and the members.
Nested Classes
Inner classes, nested static classes and even anonymous classes all have names which you can determine with Class.
getName(). You will discover $ replacing the dots in nested class names, e.g. “javax.swing.text.html.HTMLEditorKit$Parser”
or com.mindprod.americantax.AmericanTax$1. I’ not sure if you could use Class.
forName to create instances of inner classes. You can’t create an instance of an
inner class without attaching it to an instance of an outer class; I don’t know about Class
objects. Please try the experiment and let me know.
Class Names
Dynamic Class Loading
You can also dynamically construct new objects whose implementing code did not even exist at compile time and call
methods on those objects.
To keep thing simple, when you have variable classes, they all implement some interface, abstract class or base class,
in this case HolInfo:
String className = "com.mindprod.holidays.Christmas";
HolInfo holidayDelegate = (HolInfo)( Class.forName( className ).newInstance() );
String celebrated = holidayDelegate.getHowCelebrated();
To go the other way, to get the class name from an object, use obj.getClass().getName().
For a practical example of the technique,
Holiday Calculator: source also uses Class.forName
Learn To Count: source code to allow you to add new language translators or calculators or classes for new holidays, without modifying or recompiling the program; you just add the class names to a properties file
ClassLoader.findLoadedClass will let you find out if a class
has already been loaded, without requesting that it be loaded if it is not loaded already.
Sample Code to Dynamically Load Classes
Here is some code that dynamically loads classes, given just the unqualified class name. It looks in two different
packages. It caches the classes it finds. The public method returns instances of the named
class that implement the Macro interface, not Class objects.
This code is the guts of the HTML Static Macros engine. The key tools are Class. forName
and Class. asSubclass. It does not need to resort to a custom ClassLoader.
And if this essay did not overamp your brain already, have a look at this code to detect whether a class has been loaded
already.
Finding Classes
If the class you are looking for is on the classpath, you can find out which directory or jar or URL it came from with
code like this:
Sometimes the code may not even have a location, e.g. it was dynamically generated on the fly, either by generating Java
source and compiling it with the internal compiling class (sun.tools.javac.
Main or generating byte codes on the fly (JASM).
Warning
Don’t go frivolously using classForName since it will allocate the statics
and load all the methods for that class.
Learning More
Sun’s Javadoc on the
Class class : available:
Sun’s Javadoc on
Class.
forName : available:
Sun’s Javadoc on
Class.
getComponentType : available:
Sun’s Javadoc on
ClassLoader.
findLoadedClass : available: