8.4 Working with Class Objects
The result of loading a class with your own ClassLoader is an object of type Class that represents the class you just loaded. Once that class has been resolved, you can use it. But what can you use it for? There are no special JVM instructions for working with Class objects.
Class supports several methods that mimic certain instructions. You can create an instance of this class with newInstance. This creates a new instance of whatever Class represents, invokes the default constructor (the one that takes no arguments), and returns it to the calling code as an Object.
For example, suppose you've created a Logo-to-JVM compiler that turns Logo programs into bytecodes, then runs them. The class generated is a subclass of LogoProgram, which has a method called run to run the compiled Logo program. Here's how you might use such a compiler:
// Make a loader ByteArrayClassLoader loader = new ByteArrayClassLoader(); // Compile a Logo program into the class Program1 byte bytecodes = LogoCompiler.compile( "Program1", "PenDown Forward :X Left 90 Forward :Y Left 90 Forward :X Left 90"); // Cache the definition in the class loader loader.store("Program1", bytecodes); // Load it and resolve it Class programOneClass = loader.loadClass("Program1", true); // Create an instance of Program1 Object o = programOneClass.newInstance();
The reference returned from newInstance is an instance of class Program1. However, you can't use any of the Program1 methods on it since the Java program doesn't know what methods it has. All the Java program can be sure of is that it's an Object.
You know, however, that the LogoCompiler creates all objects as subclasses of LogoProgram. You can cast it to a LogoProgram, and use those methods. This involves a dynamic cast; if the object isn't really a LogoProgram, then a ClassCastException will be thrown. If LogoProgram has a method called run, then you can do this:
LogoProgram aProgramOneInstance = (LogoProgram) o; // Dynamic // cast aProgramOneInstance.run();