Even more, you can ask it to load a specific class based on its name, which allows you to design powerful abstract models painlessly. Of course, you can do the same thing with C or C++, but things are trickier — dynamically loadable modules are not easy to deal with. (You could also use link sets.)
As an example, let's consider (a simplification of) a set of generic classes for unit testing that I've written as part of a university project:
- Test: An abstract class to implement unit tests. Each class in the project will have another class dedicated to testing, which will inherit this one. For example, given a Foo class, there will be a TestFoo that does whatever is appropriate to ensure that Foo works.
- Tester: A generic driver that, based on commands given in the standard input, loads the appropriate test class, runs its unit tests and verifies the results based on prerecorded (correct) output values.
The Tester class receives a class name (Foo in our example) on the program's standard input, among a set of arguments that describe the unit test to be executed. Based on this name, it tries to load its corresponding testing class and, if it succeeds, it executes the appropriate methods. This is only possible because all testing classes have Test as the common ancestor.
As a code example, assume a className variable that holds the name read from standard input and a opName variable that has the name of the operation to be tested:
String className, opName;It is up to your imagination how you use this feature, but, as you can see, it is extremely useful.
/* Read className and opName from stdin. */
try {
Class c = Class.forName("Test" + className);
Test t = (Test)c;
t.execute(opName);
} catch (Exception e) {
/* Catching Exception for simplicity. */
}