Channels ▼
RSS

Reflection


Java Solutions August 2001/import java.*

import java.*: Reflection

Chuck Allison

Chuck does a little “reflecting” as he brings this column to a close — but only a little. You shouldn’t do much either.


I’ve 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 I’ve 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 haven’t 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 don’t 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 you’re 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 you’re 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 c

The 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 doesn’t 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 can’t 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              boolean

This 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 type’s class object is its name, but for real classes you can find out just about everything. In Listing 2, I trace a class’s 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 you’re 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 class’s 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 don’t 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. (That’s 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, it’s 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 you’re 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 hadn’t 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

I’m a little reluctant to write this section. When I tell you that you can mimic C-like function pointers in Java, I just know you’re going to be tempted to use them the same way you do in C, but you shouldn’t. 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 you’d 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, I’ve 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 you’re after isn’t in the class itself, the run-time system will look in superclasses to find it. Be prepared to handle a NoSuchMethodException if the method doesn’t exist. To invoke the method, you pass the object to invoke it for if it’s 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. It’s 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 haven’t 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. Isn’t reflection fun? It’s almost too fun. I hope you find little need for it. I’m 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 that’s not what you’re doing, let polymorphism and good object-oriented design solve your problems instead.

Notes

[1] I’m 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. He’s 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. You can contact him through his website at <www.freshsources.com>.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video