If you don't know the precise type of an object, RTTI will tell you. However, there's a limitation: The type must be known at compile time in order for yo uto detect it using RTTI and to do something useful with the information. Put another way, the compiler must know about all the classes you're working with.
This doesn't seem like that much of a limiation at first, but suppose you're given a reference to an object that's not in your program space. In fact, the class of the object isn't even available to your program at compile time.
In a traditional programming environment, this seems like a far-fetched scenario. But as we move into a larger programming world, there are important cases in which this happens. The first is component-based programming, in which you build projects using Rapid Application Development (RAD) in an Application Builder Integrated Development Environment, which I shall refer to simplyas an IDE. This is a visual approach to creating a program by moving icons that represent components onto a form. These components are then configured by setting some of their values at program time. This design-time configuration requires that any component be instantiable, that is exposes parts of itself, and that it allows its properties to be read and mofified. In addition, components that handle Graphical User Interface (GUI) events must expose information about appropriate methods so that the IDE can assist the programmer in overriding thse event-handling methods. Reflection provides the mechanism to detect the available methods and produce the method names. Java provides a structure for component-based programming through JavaBeans (described in the Graphical User Interface chapter).
Another compelling motivation for discovering class information at run time is to provide the ability to create and execute objects on remote platforms, across a network. This is call Remote Method Invocation (RMI), and it allows a Java program to have objects distributed across many machines.
This distribution can happen for a number of reasons.
The class Class supports the concept of reflection, along with the java.lang.reflect library which contains the class Field, Method, and Constructor (each of which implements the Member interface). Objects of these types are created by the JVM at run time to represent the corresponding member in the unknown class. You can then use the Constructor to create new objects, the get() and set() methods to read and modify the fields associated with Field objects, and the invoke() method to call a method associated with a Method object. in addition, you can call the convenience methods getFields(), getMethods(), getConstructors(), etc, to return arrays of the objects representing the fields, methods, and constructors. (You can find out more by looking up the class Class in the JDK documentation.) Thus, the class information for anonymous objects can be completely determined at run time, and nothing need be known at compile time.
It's important to realize that there's nothing magic about reflection. When you're using reflection to interact with an object of an unknown type, the JVM will simply look at the object and see that it belongs to a particular class (just like ordinary RTTI). Before anything can be done with it, the Class object must be loaded. Thus, the .class file for that particular type must still be available to the JVM, either on the local machine or across the network. So the true difference between RTTI and reflection is that with RTTI, the compiler opens and examines the .class file at compile time. Put another way, you can call all the methods of an object in the "normal" way. With reflection, the .class file is unavailable at complile time; it is opened and examined by the runtime environment.
A class method extractor
Normally you won't need to use the reflection tools directly, but they can be helpful when you need create more dynamic code. Reflection is in the language to support other Java features, such as object serialization and JavaBeans. However, there are times when it's quite useful to dynamically extract information about a class.
Consider a class method extractor. Looking at a class definition source code or JDK documentation shows only the methods that are defined or overriddedn within that class definition. But there might be dozens more available to you that have come from base classes. To locate these is both tedious and time consuming. Fortunately, reflection provides a way to write a simple tool that will automatcially show you the entire interface.
import java.lang.reflect.*;
import java.util.regex.*;
public class ShowMethods {
private static String usage = "usage:\n" + "ShowMethods qualified.class.name\n" + "To show all methods in class or:\n" +
"ShowMethods qualified.class.name word\n" + "To search for methods involving 'word'";
private static Pattern p = Pattern.compile("\\w+\\.");
public static void main(String[] args){
if(args.length < 1){
System.out.println(usage);
System.exit(0);
}
int lines = 0;
try{
Class<?> c = Class.forName(args[0]);
Method[] methods = c.getMethods();
Constructor[] ctors = c.getConstructors();
if(args.length == 1){
for(Method method : methods){
System.out.println(p.matcher(method.toString()).replaceAll(""));
System.out.println("==" + method.toString());
}
for(Constructor ctor : ctors){
System.out.println(p.matcher(ctor.toString()).replaceAll(""));
}
lines = methods.length + ctors.length;
} else {
for(Method method : methods){
if(method.toString().indexOf(args[1]) != -1){
System.out.println(p.matcher(method.toString()).replaceAll(""));
lines++;
}
}
}
} catch(ClassNotFoundException e){
System.out.println("No such class: " + e);
}
}
}
/* Output:
public static void main(String[])
==public static void ShowMethods.main(java.lang.String[])
public native int hashCode()
==public native int java.lang.Object.hashCode()
public final native Class getClass()
==public final native java.lang.Class java.lang.Object.getClass()
public final void wait() throws InterruptedException
==public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void wait(long,int) throws InterruptedException
==public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void wait(long) throws InterruptedException
==public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean equals(Object)
==public boolean java.lang.Object.equals(java.lang.Object)
public final native void notify()
==public final native void java.lang.Object.notify()
public final native void notifyAll()
==public final native void java.lang.Object.notifyAll()
public String toString()
==public java.lang.String java.lang.Object.toString()
public ShowMethods()
*/