Sponsored Link •
This article gives advice on using runtime class information in Java programs. It talks about the method area of the JVM and the structure of Java objects, upcasting and downcasting, polymorphism and dynamic binding,
java.lang.Classand reflection, and -- perhaps most importantly -- reveals how best to ask a hippopotamus to dance.
One of the cool things about Java's object model is that Java objects are "conscious": given a reference to an object, you can get information about that object's class. This "runtime class information" makes possible all kinds of interesting designs and implementation techniques. But how are we to use this capability?
When I think about Java's support for runtime class information, two clichés come to my mind:
1. Information is power.
In our case, runtime class information gives power to the programmer because he or she has more information to work with. This is a good thing.
2. Power corrupts.
Alas, in our case, runtime class information can be abused in designs.
The question I attempt to answer in this article is: How can you take advantage of the cool runtime class information offered by Java objects without being accused of abuse of power?
How runtime class information works
Before I delve into guidelines, I'd like to give you some background on how runtime class information works in Java.
Every class or interface you write in the Java programming language defines a new type for your program to use. Once you define a new type, you can declare variables of that type. A type defines a set of operations that may be performed on variables of that kind and the meaning of those operations.
If you define a class
Hippopotamus, for example, you then
can declare variables of type
Hippopotamus. On such
variables, the Java virtual machine (JVM) will allow you to perform
operations defined for type
Hippopotamus, but won't allow
any other operations. If class
Hippopotamus declares a
takeBath() method, for example, the JVM will allow
you to invoke
takeBath() on a variable of type
When you compile your class or interface, the Java compiler
(if it is fully pleased with your work) will give you a class file.
The class file is an intermediate-compiled binary format for
describing a Java type (a class or interface). The class file for
Hippopotamus, for example, would contain
all information needed to define that type, including things like:
private, and so on)
When a JVM loads a type (a class or interface), the JVM stores information about that type in a logical portion of its memory called the method area. The type information stored in the method area corresponds to the information stored in the class file, but unlike the class file, the structure and organization of the information in the method area is not defined by the Java specifications. The designers of each JVM decide how to store the information they parse from Java class files in the method area of their JVM implementation.
For every type it loads, the JVM creates an instance of class
to "represent" the type to the application. Arrays, because they
are full-class objects in Java, get
objects too. (Every array of the same element type and dimension
shares the same
Class object gives you access to the
information stored in the method area for the type the
Class object represents.
Although the Java specifications don't define a layout or organization for objects on the heap -- that is the decision of each JVM designer -- the specifications require that object images be in some way connected to the type data for the object's class. One approach open to a JVM designer, for example, is to include a pointer into the method area as part of each object image. Given only a reference to an object, every JVM must be able to get at the type information stored in the method area for that object.