Chuck does a little reflecting as he brings this column to a close but only a little. You shouldnt do much either.
Ive been doing a little reflecting lately. This column began in January 1999 with these words:
Hello again. import java.* invites you, the C/C++ programmer, to learn Java... . I will be examining all aspects of the language, library, and culture, but from a C/C++ perspective.
To explore the entire Java library would take more years than I care to think about, but I believe Ive covered most of the language. Since I have recently accepted the position of Senior Editor for CUJ, this will have to be the last installment of import java.*, so I would like to take this opportunity to cover the one language feature I havent yet mentioned: reflection.
Meta Programming
The first thing to say about reflection in Java is that you should almost never use it. Reflective programming, also known as meta programming, gives you access to information you usually dont need. It allows you, for instance, to inspect an object at run time to determine its dynamic type. Whether a particular object reference actually points to an object of the indicated type or a subclass is irrelevant, however, in most situations, because you want to let polymorphism do its work.
So when do you need reflection? If youre in the business of writing debuggers or class browsers or some such software, then you need it, and nothing else will do. Under the assumption that you will find yourself there someday, this article shows you the basics.
Class Objects
For every class in Java there is a corresponding singleton object of type Class, instantiated when the class is loaded, and which holds information about that class. You can obtain that object in four different ways. If you have the name of the class available when youre coding, you can use a class literal, as in
Class c = MyClass.class;For completeness, the primitive types also have a class object, and you can get your hands on them with the class literal technique, or from the TYPE field of the corresponding wrapper class:
Class c = int.class; Class c2 = Integer.TYPE; // same // object as cThe forName method always requires a fully-qualified class name. A second and more flexible avenue to a class object is to give the fully qualified class name as a parameter to Class.forName, as the following statements illustrate.
Class c = Class.forName("MyClass"); Class c = Class.forName("java.lang.String");A third method for getting class objects is to call Object.getClass on behalf of an object instance:
// "o" can be any object: Class c = o.getClass();The fourth way of getting class objects is to call the reflection methods defined in Object.Class itself, which I use throughout this article starting in the next section. The program in Listing 1 illustrates the first three techniques. When you use ObjectgetClass, you always get the class corresponding to the dynamic type of the object. In Listing 1, for example, it doesnt matter that I store a reference to a Sub object in a Super variable since the actual object is an instance of Sub, the class object returned is Sub.class. The Class.forName method will throw a ClassNotFoundException if the class cant be loaded. As you can see, Class.toString prints the word class or interface as needed. You can also see that arrays are instances of classes with interesting names, formed with left brackets (as many as there are array dimensions) followed by one of the following letters, depending on the underlying component class:
B byte C char D double F float I int J long L<classname>; S short Z booleanThis explains why you see "class [F" and "class [LSuper;" in the output of Listing 1.
Okay, now that you have a class object, what can you do with it? Lots. The only interesting information in a primitive types class object is its name, but for real classes you can find out just about everything. In Listing 2, I trace a classs ancestry all the way back to the Object root class with the Class.getSuperClass method. Since we typically depict superclasses above subclasses, I use a stack [1] to store all the class names as I walk up the inheritance tree, so I can eventually print them out in that top-down order. The class java.lang.Object is the only class that returns null for the Class.getSuperClass method; I use this fact to halt the process.
The program in Listing 3 goes a little further by also detecting any interfaces a class implements by calling Class.getInterfaces, or, if the class represents an array, the program discovers the type of its components by calling Class.getComponentType. If a class object returns false for calls to isInterface, isArray, and isPrimitive, then it must be a simple class. The output reveals that arrays are implicitly cloneable and serializable, which is a Good Thing, since there is no syntax that allows you to declare them so.
On Further Reflection
If youre writing a browser or debugger, you will surely want more than just the name of a class. There are methods to get all the fields, constructors, methods, and modifiers of a class, which are represented by instances of the classes Field, Constructor, Method, and Modifier, respectively. They are all defined in the package java.lang.reflect. The modifiers include the access specifiers public, private, and protected, as well as static, final, and abstract. If a class represents an interface, the keyword interface appears in the list of modifiers as well. These keywords are encoded in an integer returned by Class.getModifiers. You can query the integer code with suitable Modifier class constants, or you can just get the string representation for all modifiers in a single string by passing the integer to the static method Modifier.toString, as I do in Listing 4.
This program produces a listing similar in syntax to the original class definition minus the method bodies (similar to a class declaration with prototypes in C++). The first thing ClassInspector2.inspect does is determine the package, if any, that the outer class it received as a parameter resides in. Then it gets the classs modifiers and prints them along with the keyword class, if applicable, and finally the class or interface name. It then displays the superclass extended and any interfaces implemented by the class, like Listing 3 did.
Now the fun begins. My doFields method calls Class.getDeclaredFields, which returns an array of Field objects representing all of the fields declared in the class, irrespective of access specification. There is another method, Class.getFields, not used in this example, which returns all of the public fields in a class as well as all of the public fields inherited from all superclasses. From each Field instance, I extract its modifiers, type, and name for display. The methods doCtors and doMethods do the analogous actions for all constructors and methods declared in the class. Constructors and methods are treated differently because constructors dont have return types, and because Constructor objects can be used to create objects dynamically through class objects. Class.getParameterTypes returns an (possibly empty) array of class objects representing the types of the parameters the method takes (see the calls to doParameters in doCtors and doMethods). You can also call getExceptionTypes for constructors and methods, although I decided not to in this example.
The method Class.getDeclaredClasses returns an array of class objects containing type information for all the nested classes declared inside the class that inspect is processing. All I have to do for these is call inspect recursively, indenting appropriately for readability. (Thats what the field level is for.) The sample output from this program, found in Listing 5, is for the class java.util.TreeMap, which I chose because it illustrates all the features supported by ClassInspector2. Most of the methods and constructors have been omitted from the output listing to save page real estate.
You may find it interesting that you can get information on private fields and methods. Since the methods illustrated in Listing 4 only give you declaration information, its really no different than having access to an include file containing a class definition in C++. You can view the private declarations, but you have no access to the actual data they represent. If youre writing a debugger, though, you need to be able to access the private data. How to get that access is easy to illustrate, but difficult to thoroughly explain. The program in Listing 6 inspects arbitrary objects by determining all fields at run time, including inherited fields (ignoring those in java.lang.Object). The method Field.get yields the value of a field as an instance of java.lang.Object. If the field is a primitive, the value is automatically wrapped in an instance of the corresponding object wrapper class. Whenever you try to set or get a field, the run-time system verifies your access rights, just as the compiler does with normal, non-reflected code. If I hadnt called AccessibleObject.setAccessible(fields,true) [2] in ObjectInspector.inspect, I would have been greeted with an IllegalAccessException the first time I tried to access one of the fields in the TreeMap object, since none is public. Whether you ultimately get access permission depends on the class loader and security manager in use both topics outside the scope of this article. Suffice it to say that the default case for an application (versus an applet) allows me to get the output that appears in Listing 6 without error.
Meta Execution
Im a little reluctant to write this section. When I tell you that you can mimic C-like function pointers in Java, I just know youre going to be tempted to use them the same way you do in C, but you shouldnt. There are better ways to pass functions in C++ and Java (e.g., function objects), but that is, alas, yet another topic for another day. Anyway, yes, you can pass method references around, and, as youd expect, you can determine which method you want to execute at run time by its name string. To get a method reference, you need its name and a list of the types of its arguments. In Listing 7, Ive defined a class Foo and a class Bar, each with like-named methods (am I creative with names, or what?). To get a method reference at run time, call Class.getMethod with two arguments: the method name as a String, and an array of argument types. You can use null or an empty Class array to match methods that take no arguments. You can only get references to public methods, but if the method youre after isnt in the class itself, the run-time system will look in superclasses to find it. Be prepared to handle a NoSuchMethodException if the method doesnt exist. To invoke the method, you pass the object to invoke it for if its a non-static method and a list of expected parameters in array of Object to Method.invoke.
The program in Listing 8 shows how to invoke static methods you just use null as the first parameter to Method.invoke. Its important to remember to place the array of String, which is the argument to main, of course, in the first position of the Object array representing the arguments passed to main. This particular program is a program launcher it finds the main method for the class represented by args[0] and passes the remaining command-line arguments to that main.
Summary
I havent shown it here, but there is a newInstance method in the Constructor class for creating objects, and there is also an Array class in java.lang.reflect for creating and manipulating arrays dynamically. Isnt reflection fun? Its almost too fun. I hope you find little need for it. Im sure you can appreciate how it is useful for inspecting objects at run time, like in a class browser or a program that processes JavaBeans. If thats not what youre doing, let polymorphism and good object-oriented design solve your problems instead.
Notes
[1] Im using the LinkedList collection class to implement a stack. For more on collections see the September 2000 installment of import java.*.
[2] Field, Constructor, and Method all derive from AccessibleObject.
Chuck Allison is senior editor of CUJ and has been a contributing editor since 1992. He began his career as a software engineer in 1978, and for most of the 1990s was a contributing member of the C++ Standards committee. Hes the author of the intermediate-level text, C & C++ Code Capsules (Prentice-Hall, 1998), based on articles published in this journal. During the day Chuck is an Assistant Professor of Computer Science at Utah Valley State College.