Inspecting a Class Instance
Home ] Up ] Reconstructing a Class ] [ Inspecting a Class Instance ] Instantiating an Object ] Creating an Array ] Calling a Method ] An Example ]

 

 

Horstmann and Cornell, in CORE Java, Volume I : Fundamentals, create a useful little class, ObjectAnalyzer, that allows you to peek into class instances at run time to determine their internal state. This could be useful for debugging, etc. ObjectAnalyzer is a class that has only static methods; it is non-instantiatable.

Here is a version modified to work under JDK 1.1 and beyond. It has also been enhanced to output information about arrays as well as classes:

package reflection;

import java.lang.reflect.Array;
import java.lang.reflect.Field;


/**
*   This class allows the programmer to peek into
*   a specified class, and also to provide a generic
*   equals() mechanism.
*
*   @author Horstmann & Cornell, CORE Java 1.2, Vol I, p214
*   @author Bryan J. Higgs, modified & extended 29 Dec 1999
*/
public class ObjectAnalyzer
{
    private ObjectAnalyzer()
    {
        // Prevent instantiation
    }
    
    public static String toString(Object obj)
    {
        return toString(obj, 0);
    }
    
    private static String toString(Object obj, 
                                   int indentLevel)
    {
        String indent = "";
        for (int i = 0; i < indentLevel; i++)
            indent += " ";
            
        Class c = obj.getClass();
        if (c.isArray())
        {
            Class type = c.getComponentType();
            String typeString = type.getName();
            if (type.isArray())
                typeString = getArrayType(type);
                
            return indent + "Array of " + typeString + "\n" +
                   getArrayContents(obj, indentLevel);
        }
            
        String r = indent + c.getName();
        Class sc = c.getSuperclass();
        if (sc != null && !sc.equals(Object.class))
            r += " extends " + sc;
        r += "\n";
        Field[] fields = c.getDeclaredFields();
        for (int i = 0; i < fields.length; i++)
        {
            Field field = fields[i];
            r += field.getName() + "=";
            String s = "???";// Expect access problems
            try
            {
                Object value = field.get(obj);
                Class vc = value.getClass();
                if (!vc.isArray())
                    s = value.toString();
                else
                {
                    s = "\n";
                    s += getArrayContents(value, 
                                          indentLevel + 1);
                }
            }
            catch(NullPointerException e)
            {
                s = "null";
            }
            catch(IllegalAccessException e)
            {}
            r += s;
            if (!r.endsWith("\n"))
                r += "\n";
        }
        return r;
    }
    
    private static String getArrayContents(Object obj, 
                                           int indentLevel)
    {
        String indent = "";
        for (int i = 0; i < indentLevel; i++)
            indent += " ";
            
        Class c = obj.getClass();
        String r = "";
        int length = Array.getLength(obj);
        for (int i = 0; i < length; i++)
        {
            r += indent + "[" + i + "]=";
            String s = "???";// Expect access problems
            try
            {
                Object value = Array.get(obj, i);
                Class vc = value.getClass();
                s = "(" + getArrayType(vc) + ")";
                if (!vc.isArray())
                {
                    s += value.toString();
                }
                else
                {
                    s += "\n" + 
                         getArrayContents(value, 
                                          indentLevel + 1);
                }
                
            }
            catch(NullPointerException e)
            {
                s = "null";
            }
            r += s;
            if (!r.endsWith("\n"))
                r += "\n";
        }
        return r;
    }
    
    private static String getArrayType(Class c)
    {
        if (!c.isArray())
            return c.getName();
        else
        {
            // Use recursion to construct proper string
            String type = getArrayType(c.getComponentType());
            return type + "[]";
        }
    }
}

Here is a small test program to exercise it:

package reflection;

import java.util.Date;
import java.util.Vector;

public class ObjectAnalyzerTest
{
    public static void main(String[] args)
    {
        String[] strings = new String[] {"Fred", "Joe", "Martha"};
        System.out.println("strings: " + 
                           ObjectAnalyzer.toString(strings));
        
        System.out.println("System.out: " + 
                           ObjectAnalyzer.toString(System.out));
        
        Person[] parents = new Person[] 
        { 
            new Person("Vernon Clydesdale", 48), null
        };
        Person person = 
             new Person("Myrtle A. Fibbertigibbet", 24, parents);
        System.out.println("Person: " + 
                           ObjectAnalyzer.toString(person));
        
        Object[] objects = new Object[]
        {
            "I am a String", new Person("Lionel Barksdale", 54),
            new Object[]
            {
                "Another String", new Long(45L), new Vector(),
            },
            new Double(83.4), new Date()
        };
        System.out.println("objects: " + 
                           ObjectAnalyzer.toString(objects));
    }
    
    //// Nested class for testing ////
    static class Person
    {
        Person(String name, int age)
        {
            this(name, age, null);
        }
        
        Person(String name, int age, Person[] parents)
        {
            m_name = name;
            m_age  = age;
            m_parents = parents;
            m_count++;
        }
        
        public String toString()
        {
            return m_name;
        }
        
        ///// Data ////
        String      m_name;
        int         m_age;
        static int  m_count = 0;
        Person[]    m_parents;
    }
}

This outputs the following:

strings: Array of java.lang.String
[0]=(java.lang.String)Fred
[1]=(java.lang.String)Joe
[2]=(java.lang.String)Martha

System.out: java.io.PrintStream extends class java.io.FilterOutputStream
autoFlush=???
trouble=???
textOut=???
charOut=???
closing=???

Person: reflection.ObjectAnalyzerTest$Person
m_name=Myrtle A. Fibbertigibbet
m_age=24
m_count=2
m_parents=
 [0]=(reflection.ObjectAnalyzerTest$Person)Vernon Clydesdale
 [1]=null

objects: Array of java.lang.Object
[0]=(java.lang.String)I am a String
[1]=(reflection.ObjectAnalyzerTest$Person)Lionel Barksdale
[2]=(java.lang.Object[])
 [0]=(java.lang.String)Another String
 [1]=(java.lang.Long)45
 [2]=(java.util.Vector)[]
[3]=(java.lang.Double)83.4
[4]=(java.util.Date)Wed Dec 29 16:51:09 EST 1999

Note that the program cannot output the contents of the private fields in System.out, because Java's access control won't allow it. In JDK 1.2, however, they have added the ability to override the access control, subject to SecurityManager's approval.

Here's a version of the program that adds this support (but note that it will only compile with JDK 1.2 or higher):

package reflection;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.AccessibleObject;


/**
*   This class allows the programmer to peek into
*   a specified class, and also to provide a generic
*   equals() mechanism.
*
*   @author Horstmann & Cornell, CORE Java 1.2, Vol I, p214
*   @author Bryan J. Higgs, modified & extended 29 Dec 1999
*/
public class ObjectAnalyzer2
{
    private ObjectAnalyzer2()
    {
        // Prevent instantiation
    }
    
    public static String toString(Object obj)
    {
        return toString(obj, 0);
    }
    
    private static String toString(Object obj, 
                                   int indentLevel)
    {
        String indent = "";
        for (int i = 0; i < indentLevel; i++)
            indent += " ";
            
        Class c = obj.getClass();
        if (c.isArray())
        {
            Class type = c.getComponentType();
            String typeString = type.getName();
            if (type.isArray())
                typeString = getArrayType(type);
                
            return indent + "Array of " + typeString + "\n" +
                   getArrayContents(obj, indentLevel);
        }
            
        String r = indent + c.getName();
        Class sc = c.getSuperclass();
        if (sc != null && !sc.equals(Object.class))
            r += " extends " + sc;
        r += "\n";
        Field[] fields = c.getDeclaredFields();
        try
        {
            AccessibleObject.setAccessible(fields, true);
        }
        catch(SecurityException e)
        {
        }
        for (int i = 0; i < fields.length; i++)
        {
            Field field = fields[i];
            r += field.getName() + "=";
            String s = "???";// Expect access problems
            try
            {
                Object value = field.get(obj);
                Class vc = value.getClass();
                if (!vc.isArray())
                    s = value.toString();
                else
                {
                    s = "\n";
                    s += getArrayContents(value, 
                                          indentLevel + 1);
                }
            }
            catch(NullPointerException e)
            {
                s = "null";
            }
            catch(IllegalAccessException e)
            {}
            r += s;
            if (!r.endsWith("\n"))
                r += "\n";
        }
        return r;
    }
    
    private static String getArrayContents(Object obj, 
                                           int indentLevel)
    {
        String indent = "";
        for (int i = 0; i < indentLevel; i++)
            indent += " ";
            
        Class c = obj.getClass();
        String r = "";
        int length = Array.getLength(obj);
        for (int i = 0; i < length; i++)
        {
            r += indent + "[" + i + "]=";
            String s = "???";// Expect access problems
            try
            {
                Object value = Array.get(obj, i);
                Class vc = value.getClass();
                s = "(" + getArrayType(vc) + ")";
                if (!vc.isArray())
                {
                    s += value.toString();
                }
                else
                {
                    s += "\n" + 
                         getArrayContents(value, 
                                          indentLevel + 1);
                }
                
            }
            catch(NullPointerException e)
            {
                s = "null";
            }
            r += s;
            if (!r.endsWith("\n"))
                r += "\n";
        }
        return r;
    }
    
    private static String getArrayType(Class c)
    {
        if (!c.isArray())
            return c.getName();
        else
        {
            // Use recursion to construct proper string
            String type = getArrayType(c.getComponentType());
            return type + "[]";
        }
    }
}
 
The page was last updated February 19, 2008