Uses of Class.forName
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/plug-in approach are JDBC (Java Data Base Connectivity)
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 (Java Virtual Machine)
byte codes, class file images in RAM (Random Access Memory),
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:
Class.forName 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
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’m 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:
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 (Hypertext Markup Language) Static Macros engine. The
key tools are Class.forName and Class.
And if this essay did not overamp your brain already, have a look at this code to
detect whether a class has been loaded
Finding Classes
If the class you are looking for is on the
classpath, you can find out which directory or jar or URL (Uniform Resource Locator)
it came from with
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 Class.forName
since it will allocate the statics and load all the
methods for that class.
- Class.forName just loads the
class. It does not run the static initialisation code.
To trigger the static init code, execute some dummy
static method.
Limitations
When I first encountered Java, I was very excited about the notion of interfaces
and dynamic loading. I thought it would let people plug in their own code to every
conceivable utility.
There are two catches:
- arranging that java.exe will look for your dynamic
class in the place where it is. It will not usually be bundled in the original
jar.
- arranging that java.exe will look for any auxiliary
classes your plug-in needs in the place where they live.
A garden variety jar without a Class-Path entry in the manifest, prevents java
from looking anywhere else for classes. The same problem applies to java on other
platforms, Java Webstart and the Java Applet plug-in.
How can you get around the problem?
- Skirt the problem by putting all classes in the original jar. This is not very
dynamic or open.
- You can put a classpath inside the jar. You can use that to do relative
references, i.e. via same directory or URL
that hosts the referencing jar. Here is what the manifest entry might look like
Class-Path: lib/antlr-runtime-3.0.jar lib/core-3.2.3.v_686_R32x.jar li
b/derby.jar lib/drools-compiler-4.0.7.jar lib/drools-core-4.0.7.jar l
ib/mvel-1.3.1-java1.4.jar lib/mysql-connector-java-5.1.7-bin.jar lib/
ojdbc5.jar lib/postgresql-8.3-603.jdbc3.jar
There are a number of weirdnesses:
- Lines cannot be longer than 72 characters
- The path entries are separated by spaces
- Lines are wrapped and indented by one space.
- Relative paths are relative to where the jar is stored and executed
from.
- Class-Path contains a dash and capital letters.
This is one of the ugliest file formats I have ever encountered, however,
ANT (A Neat Tool) will build it for you.
- For more advanced cases, you can instantiate a URLClassLoader with the URL
for where to look for dynamic loaded classes.
- Use a JEE containers or Tomcat. They have dynamic loading built-in.
Dynamic class loaders bring with them their own set of problems:
- Class.equals() will fail
on classes loaded by different classloaders, as will Object.equals().
- You can’t unload a class just like that, as the ClassLoader keeps references to all loaded classes. You need to
unload the ClassLoader too. This makes it tricky to
reload plug-ins without a JVM restart.
Learning More
Oracle’s Javadoc on
Class class : available:
Oracle’s Javadoc on
Class.forName : available:
Oracle’s Javadoc on
Class.getComponentType : available:
Oracle’s Javadoc on
ClassLoader.findLoadedClass : available: