Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Design with runtime class information

How to make use of runtime class information in Java programs

  • Print
  • Feedback

Page 4 of 5

A good general rule is that you should strive not to write code that doesn't know what's coming, but sometimes you can't avoid it. In such cases, instanceof is the preferred way to find out whether you've got a specific type you'll want to treat specially.

Another legitimate, though less common, way to use instanceof is to check for a tag interface. Sometimes an interface is defined without any members, merely to serve as a "tag" for classes. For example, the Serializable interface contains no fields or methods. Serializable's sole purpose is to indicate that an object allows serialization.

When you use instanceof to check for a tag interface, you are not so much asking an object Can you do a particular thing for me? but rather, Can I do a particular thing to you? Instead of determining whether the object has a particular method you want to invoke, you find out whether you are "allowed" to use the object in some way that doesn't necessarily involve invoking its methods.

Class 'Class'
Where casts, instanceof, and instance method invocations give you a taste of runtime class information, class java.lang.Class gives you a feast: Instances of class java.lang.Class represent the most abundant source of runtime class information in the JVM. Once you have a reference to an object's Class instance, you have access to a wealth of information about that object's class.

You can get a reference to any object's Class instance by invoking getClass() on the reference, as in:

    static void printClassInfo(Object o) {

System.out.println("------------------------");
Class c = o.getClass(); // ...


If you know the type at compile time, you can get a reference to the class instance for a type with the syntax: <typename>.class. For example, the expression Hippopotamus.class would yield a reference to the Class instance for class Hippopotamus. Once you have a reference to a Class, you can get at all kinds of information about the represented type, some of it via the reflection API.

Here's an application that accesses and prints some of the information available from Class objects:

// In file rtci/ex2/Hippopotamus.java
class Hippopotamus {

private String yawnAdjective;
Hippopotamus(String yawnAdjective) { this.yawnAdjective = yawnAdjective; }
void yawn() { System.out.println(yawnAdjective + " yawn!"); } }

// In file rtci/ex2/DancingHippopotamus.java class DancingHippopotamus extends Hippopotamus {
DancingHippopotamus(String yawnAdjective) { super(yawnAdjective); }
void dance() { System.out.println("Dance!"); } }

// In file rtci/ex3/Example3.java import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.lang.reflect.*;
class Example3 {
public static void main(String[] args) {
ArrayList hippos = new ArrayList(); hippos.add(new Hippopotamus("Big")); hippos.add(new DancingHippopotamus("Little")); hippos.add(hippos); hippos.add(new String("Hi There!"));
Iterator it = hippos.iterator(); while (it.hasNext()) { printClassInfo(it.next()); } }
static void printModifiers(int modifiers) {
if (Modifier.isPrivate(modifiers)) { System.out.print("private "); } else if (Modifier.isProtected(modifiers)) { System.out.print("protected "); } else if (Modifier.isPublic(modifiers)) { System.out.print("public "); }
if (Modifier.isAbstract(modifiers)) { System.out.print("abstract "); } if (Modifier.isStatic(modifiers)) { System.out.print("static "); } if (Modifier.isFinal(modifiers)) { System.out.print("final "); } if (Modifier.isTransient(modifiers)) { System.out.print("transient "); } if (Modifier.isVolatile(modifiers)) { System.out.print("volatile "); } if (Modifier.isSynchronized(modifiers)) { System.out.print("synchronized "); } if (Modifier.isNative(modifiers)) { System.out.print("native "); } }
static void printClassInfo(Object o) {
System.out.println("------------------------");
Class c = o.getClass();
System.out.println("Name: " + c.getName());
Class superclass = c.getSuperclass(); if (superclass != null) { System.out.println("Superclass: " + superclass.getName()); }
System.out.println("Interfaces:"); Class[] interfaces = c.getInterfaces(); for (int i = 0; i < interfaces.length; ++i) { System.out.println("\t" + interfaces[i].getName()); }
System.out.println("Fields:"); Field[] fields = c.getDeclaredFields(); for (int i = 0; i < fields.length; ++i) { System.out.print("\t"); printModifiers(fields[i].getModifiers()); System.out.println((fields[i].getType()).getName() + " " + fields[i].getName() + ";"); }
System.out.println("Methods:"); Method[] methods = c.getDeclaredMethods(); for (int i = 0; i < methods.length; ++i) {
System.out.print("\t"); printModifiers(methods[i].getModifiers());
System.out.print((methods[i].getReturnType()).getName() + " " + methods[i].getName() + "(");
Class[] params = methods[i].getParameterTypes(); for (int j = 0; j < params.length; ++j) { System.out.print(params[j].getName()); if (j != 0 && j != params.length - 1) { System.out.print(", "); } }
System.out.println(");"); } } }


Here's the output of the Example3 application:

------------------------
Name: Hippopotamus
Superclass: java.lang.Object
Interfaces:
Fields:
    private java.lang.String yawnAdjective;
Methods:
    void yawn();
------------------------
Name: DancingHippopotamus
Superclass: Hippopotamus
Interfaces:
Fields:
Methods:
    void dance();
------------------------
Name: java.util.ArrayList
Superclass: java.util.AbstractList
Interfaces:
    java.util.List
    java.lang.Cloneable
    java.io.Serializable
Fields:
    private transient [Ljava.lang.Object; elementData;
    private int size;
Methods:
    private void RangeCheck(int);
    public void add(intjava.lang.Object);
    public boolean add(java.lang.Object);
    public boolean addAll(intjava.util.Collection);
    public boolean addAll(java.util.Collection);
    public void clear();
    public java.lang.Object clone();
    public boolean contains(java.lang.Object);
    public void ensureCapacity(int);
    public java.lang.Object get(int);
    public int indexOf(java.lang.Object);
    public boolean isEmpty();
    public int lastIndexOf(java.lang.Object);
    private synchronized void readObject(java.io.ObjectInputStream);
    public java.lang.Object remove(int);
    public java.lang.Object set(intjava.lang.Object);
    public int size();
    public [Ljava.lang.Object; toArray();
    public [Ljava.lang.Object; toArray([Ljava.lang.Object;);
    public void trimToSize();
    private synchronized void writeObject(java.io.ObjectOutputStream);
------------------------
Name: java.lang.String
Superclass: java.lang.Object
Interfaces:
    java.io.Serializable
    java.lang.Comparable
Fields:
    private [C value;
    private int offset;
    private int count;
    private static final long serialVersionUID;
    public static final [Ljava.io.ObjectStreamField; serialPersistentFields;
    public static final java.util.Comparator CASE_INSENSITIVE_ORDER;
Methods:
    public char charAt(int);
    public int compareTo(java.lang.Object);
    public int compareTo(java.lang.String);
    public int compareToIgnoreCase(java.lang.String);
    public java.lang.String concat(java.lang.String);
    public static java.lang.String copyValueOf([C);
    public static java.lang.String copyValueOf([Cint, int);
    public boolean endsWith(java.lang.String);
    public boolean equals(java.lang.Object);
    public boolean equalsIgnoreCase(java.lang.String);
    public [B getBytes();
    public void getBytes(intint, [B, int);
    public [B getBytes(java.lang.String);
    private [B getBytes(sun.io.CharToByteConverter);
    public void getChars(intint, [C, int);
    public int hashCode();
    public int indexOf(int);
    public int indexOf(intint);
    public int indexOf(java.lang.String);
    public int indexOf(java.lang.Stringint);
    public native java.lang.String intern();
    public int lastIndexOf(int);
    public int lastIndexOf(intint);
    public int lastIndexOf(java.lang.String);
    public int lastIndexOf(java.lang.Stringint);
    public int length();
    public boolean regionMatches(intjava.lang.String, int, int);
    public boolean regionMatches(booleanint, java.lang.String, int, int);
    public java.lang.String replace(charchar);
    public boolean startsWith(java.lang.String);
    public boolean startsWith(java.lang.Stringint);
    public java.lang.String substring(int);
    public java.lang.String substring(intint);
    public [C toCharArray();
    public java.lang.String toLowerCase();
    public java.lang.String toLowerCase(java.util.Locale);
    public java.lang.String toString();
    public java.lang.String toUpperCase();
    public java.lang.String toUpperCase(java.util.Locale);
    public java.lang.String trim();
    public static java.lang.String valueOf(char);
    public static java.lang.String valueOf(double);
    public static java.lang.String valueOf(float);
    public static java.lang.String valueOf(int);
    public static java.lang.String valueOf(long);
    public static java.lang.String valueOf(java.lang.Object);
    public static java.lang.String valueOf(boolean);
    public static java.lang.String valueOf([C);
    public static java.lang.String valueOf([Cint, int);



Well, that's a lot of information. To get at this information, the Example3 class uses java.lang.Class and the reflection API. Other aspects of the reflection API can be used not just to get information about a type, but to actually invoke methods or alter fields.

  • Print
  • Feedback

Resources
  • Bill's next book is Flexible Java http://www.artima.com/flexiblejava/index.html
  • A complete online reprint of "Chapter 7, The Linking Model," of Bill's book Inside the Java Virtual Machine http://www.artima.com/insidejvm/linkmod.html
  • The handout and slides for Bill's "Dynamic Extension in Java" talk. http://www.artima.com/javaseminars/modules/DynaExt/index.html
  • Bill recently returned from his European bike trip. Read about it at
    http://www.artima.com/bv/travel/bike98/index.html
  • The discussion forum devoted to the material presented in this article http://www.artima.com/flexiblejava/fjf/rtci/index.html
  • Links to all previous Design Techniques articles http://www.artima.com/designtechniques/index.html
  • Recommended books on Java design http://www.artima.com/designtechniques/booklist.html
  • A transcript of an e-mail debate between Bill Venners, Mark Johnson (JavaWorld's JavaBeans columnist), and Mark Balbe on whether all objects should be made into beans http://www.artima.com/flexiblejava/comments/beandebate.html
  • Object orientation FAQ http://www.cyberdyne-object-sys.com/oofaq/
  • A hearty collection of links on object orientation (numbering 7,237 at last count) http://www.rhein-neckar.de/~cetus/software.html
  • The Object-Oriented Page http://www.well.com/user/ritchie/oo.html
  • Collection of information on OO approach http://arkhp1.kek.jp:80/managers/computing/activities/OO_CollectInfor/OO_CollectInfo.html
  • Design Patterns home page http://hillside.net/patterns/patterns.html
  • A Comparison of OOA and OOD Methods http://www.iconcomp.com/papers/comp/comp_1.html
  • "Object-Oriented Analysis and Design MethodsA Comparative Review" http://wwwis.cs.utwente.nl:8080/dmrg/OODOC/oodoc/oo.html
  • Patterns discussion FAQ http://gee.cs.oswego.edu/dl/pd-FAQ/pd-FAQ.html
  • Patterns in Java AWT http://mordor.cs.hut.fi/tik-76.278/group6/awtpat.html
  • Software Technology's Design Patterns page http://www.sw-technologies.com/dpattern/
  • Previous Design Techniques articles http://www.javaworld.com/topicalindex/jw-ti-techniques.html