Java Reflection in Action, Part 2
1.7 Diagramming for reflection
Throughout this book, we use the Unified Modeling Language (UML) for diagrams like figure 4. Those familiar with UML will probably notice that figure 4 combines UML class and object diagrams. Reflection represents all of the class diagram entities at runtime using metaobjects. Therefore, combining class and object diagrams is useful for clearly communicating reflective designs.
UML diagrams typically include only classes or only non-class objects. Modeling reflection calls for combining the two and using the instanceOf dependency to connect an object with its instantiating class. UML defines the instanceOf dependency with same meaning as the Java instanceof operator. However, this book uses the instanceOf dependency only to show that an object is a direct instance of a class. For clarity, we partition figure 4 into its base level and meta-level, although that partition is not standard UML. For more detail on UML, see appendix C.
1.8.2 Exposing some surprises
In the Java reflection API, there are some relationships that may be surprising upon first glance. Discussing these relationships now prepares us for encountering them later in the book and in reflective programming in general. Being prepared in this manner allows for better reflective programming.
The isInstance method can be used to show a very interesting fact about the arrangement of the classes in the Java reflection API. The line
evaluates to true. This means that the class object for Class is an instance of itself, yielding the circular instanceOf dependency of figure 5. Class is an example of a metaclass, which is a term used to describe classes whose instances are classes. Class is Java's only metaclass.
In Java, all objects have an instantiating class, and all classes are objects. Without the circular dependency, the system must support an infinite tower of class objects, each one an instance of the one above it. Instead, Java uses this circularity to solve this problem.
Figure 5 The object fido is an instance of the Dog class. Dog is an instance of the class Class. Class is also an instance of Class. Class is a metaclass because it is a class whose instances are classes.
The circularity presented in figure 5 makes people uncomfortable because we instinctively mistrust circular definitions. However, as programmers, we are familiar with other kinds of circular definitions. For example, consider recursion. A method that uses recursion is defined in terms of itself; that is, it has a circular definition. When used properly, recursion works just fine. Similarly, there are constraints on the definition of java.lang.Class that make this circularity work just fine.
For more information about this circularity, see Putting Metaclasses to Work . Putting Metaclasses to Work is an advanced book on reflection and metaobject protocols written by one of the authors of this book. It is a good resource for readers who are interested in the theoretical and conceptual basis for reflection.
1.8.3 Another reflective circularity
Adding inheritance to our previous diagram yields the arrangement in figure 1.6. Inheritance adds more circularity to the picture. Object is an instance Class, which can be validated because the following line returns true:
Class is also a subclass of Object, validated by
which also returns true. Conceptually, we already know these facts because in Java, each object has one instantiating class, and all classes are kinds of objects. However, it is comforting that the reflective model is consistent with our previous understanding of the language.
Figure 6 Object is the top of the Java inheritance hierarchy, so classes of metaobjects, including Class, are subclasses of Object. This means that the methods of Object are part of the reflection API. All Java classes are instances of its only metaclass, Class. These two conditions create a cycle in the diagram.
The new circularity implies additional constraints on the definitions of Object and Class. These constraints are satisfied when the Java Virtual Machine loads the java.lang package. Again, a full explanation of the constraints may be found in Putting Metaclasses to Work .
Figure 6 also illustrates why Object is considered part of the reflection API. All metaobjects extend Object, and so they inherit its methods. Therefore, each of those methods can be used in reflective programming.
Reflection allows programs to examine themselves and make changes to their structure and behavior at runtime. Even a simple use of reflection allows programmers to write code that does things that a programmer would normally do. These simple uses include getting the class of an object, examining the methods of a class, calling a method discovered at runtime, and exploring the inheritance hierarchy.
The metaobject classes Class and Method represent the classes and methods of running programs. Other metaobjects represent the other parts of the program such as fields, the call stack, and the loader. Class has additional methods to support these other metaobjects. Querying information from these metaobjects is called introspection.
Metaobjects also provide the ability to make changes to the structure and behavior of the program. Using dynamic invocation, a Method metaobject can be commanded to invoke the method that it represents. Reflection provides several other ways to affect the behavior and structure of a program such as reflective access, modification, construction, and dynamic loading.
There are several patterns for using reflection to solve problems. A reflective solution often starts with querying information about the running program from metaobjects. After gathering information using introspection, a reflective program uses that information to make changes in the behavior of the program.
Each new metaobject class allows us to grow our examples in scope and value. These examples reveal lessons that we have learned and techniques that we have applied. Each one follows the same basic pattern of gathering information with introspection and then using the information to change the program in some way.
About the Authors
Dr. Ira Forman is a senior software engineer at IBM. He started working on reflection in the early 1990s when he developed IBM's SOM Metaclass Framework. Nate Forman works for Ticom Geomatics where he uses reflection in day-to-day problems. Ira and Nate are father and son. They live in Austin, Texas.
About the BookJava Reflection in Action By Ira R. Forman and Nate Forman
Published October 2004, Softbound, 300 pages
Published by Manning Publications Co.
Retail price: $44.95
Ebook price: $22.50. To purchase the ebook go to http://www.manning.com/forman.
This material is from Chapter 1 of the book.
Page 3 of 3