Background
Turing's great insight: programs are just another kind of data
Source code is text
Manipulate it line by line, or by parsing expressions
Compiled programs are data, too
Integers and strings are bytes in memory that you interpret a certain way
Instructions in methods are just bytes too
No reason why a program can't inspect itself, i.e. read its own data
How Objects Work

The Class Class
Instances of the class Class store information about classes
Class name
Inheritance
Interfaces implemented
Methods, members, etc.
Can look up instances:
By name
From an object
Showing a Type
public static void showType(PrintStream out, String className) throws ClassNotFoundException {
Class thisClass = Class.forName(className);
String flavor = thisClass.isInterface() ? "interface" : "class";
out.println(flavor + " " + className);
Class parentClass = thisClass.getSuperclass();
if (parentClass != null) {
out.println(" extends " + parentClass.getName());
}
Class[] interfaces = thisClass.getInterfaces();
for (int i=0; i<interfaces.length; ++i) {
out.println(" implements " + interfaces[i].getName());
}
out.println();
}
Output for Type Example
class java.lang.Object class java.lang.Integer extends java.lang.Number implements java.lang.Comparable class java.util.HashMap extends java.util.AbstractMap implements java.util.Map implements java.lang.Cloneable implements java.io.Serializable class Point extends java.lang.Object
More About Classes
Examining Class Contents
public static void showContents(PrintStream out, boolean hideObject, String name)
throws ClassNotFoundException {
Class cls = Class.forName(name);
out.println(name);
showMembers(out, hideObject, name + " fields", cls.getFields());
showMembers(out, hideObject, name + " constructors", cls.getConstructors());
showMembers(out, hideObject, name + " methods", cls.getMethods());
}
public static void showMembers(PrintStream out, boolean hideObject,
String title, Member[] members) {
out.println(" " + title);
for (int i=0; i<members.length; ++i) {
if (members[i].getDeclaringClass() == Object.class) {
if (hideObject) {
continue;
}
}
out.println("\t" + members[i]);
}
}
Output for Class Content Example
Note: things belonging to java.lang.Object are hidden
java.util.Map
java.util.Map fields
java.util.Map constructors
java.util.Map methods
public abstract int java.util.Map.hashCode()
public abstract java.lang.Object java.util.Map.put(java.lang.Object,java.lang.Object)
public abstract boolean java.util.Map.equals(java.lang.Object)
public abstract java.lang.Object java.util.Map.get(java.lang.Object)
public abstract int java.util.Map.size()
...etc...
Point
Point fields
Point constructors
public Point(java.lang.String,int,int)
Point methods
public java.lang.String Point.toString()
public java.lang.String Point.getName()
public void Point.setName(java.lang.String)
public int Point.getX()
public void Point.setX(int)
public int Point.getY()
public void Point.setY(int)
Getting at Members
How to access members of a specific object?
Without making raw pointers into memory part of the language
They are a rich source of errors in C/C++
Introduce a class Field
Encapsulates access to a particular field of instances of a class
Knows "where the field is" in objects of that class
Use its get() and set() methods to inspect and modify the object
Examining Fields
public static void main(String[] args) {
PublicPoint p = new PublicPoint("center", 3, 3);
showField(System.out, p, "fName");
showField(System.out, p, "fX");
showField(System.out, p, "fY");
showField(System.out, p, "fZ");
}
public static void showField(PrintStream out, Object obj, String fieldName) {
try {
Class cls = obj.getClass();
Field field = cls.getField(fieldName);
Object value = field.get(obj);
out.println(fieldName + ": " + value);
}
catch (NoSuchFieldException e) {
System.err.println(e);
}
catch (IllegalAccessException e) {
System.err.println(e);
}
}
Output for Fields Example
fName: center fX: 3 fY: 3 java.lang.NoSuchFieldException: fZ
Getting at Methods
Examine a class's methods in a similar way
The class Method subclasses Member to represent a callable method
Reports the method's return type by handing back a Class instance
Reports parameter types using an array of Class instances
Examining Methods
public static void showMethods(PrintStream out, Object obj)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
Class cls = obj.getClass();
out.println(cls.getName());
Member[] members = cls.getMethods();
for (int im=0; im<members.length; ++im) {
Method meth = (Method)members[im];
if (meth.getDeclaringClass() == cls) {
showMethod(out, (Method)members[im]);
}
}
}
public static void showMethod(PrintStream out, Method meth) {
Class returnType = meth.getReturnType();
out.print("\t" + returnType.getName() + " " + meth.getName() + "(");
Class[] paramTypes = meth.getParameterTypes();
String prefix = "";
for (int i=0; i<paramTypes.length; ++i) {
out.print(prefix + paramTypes[i].getName());
prefix = ", ";
}
out.println(")");
}
Output of Methods Example
Point
java.lang.String toString()
java.lang.String getName()
void setName(java.lang.String)
int getX()
void setX(int)
int getY()
void setY(int)
Calling Methods
Need to:
Look up a method based on its name and signature
Call a method, passing in parameters and capturing return value
Specify a signature as an array of Class objects
Specifies the types of arguments
Special values for non-reference types like int and boolean
Note: cannot select based on return type
Specify parameters as an Object array
Use Integer instead of int, etc.
Java will extract values as necessary
Three Classes With Similar Methods
public class Red {
public Red() {
}
public void left(Integer i) {
System.out.println("Red with Integer " + i);
}
public void right(String s) {
System.out.println("Red with String " + s);
}
}
public class Green {
public Green() {
}
public String left(Integer i) {
System.out.println("Green with Integer " + i);
return "Green string";
}
public void right(Integer i) {
System.out.println("Green with Integer " + i);
}
}
public class Blue {
public Blue() {
}
public Integer left(Integer i) {
System.out.println("Blue with Integer " + i);
return new Integer(99);
}
private void right(Integer i) {
System.out.println("Blue with Integer " + i);
}
}
Example of Calling Methods
public static void main(String[] args) {
// Look for method taking single integer parameter
String methodName = args[0];
Class[] signature = new Class[1];
signature[0] = Integer.class;
// Look up named method for each class
for (int i=1; i<args.length; ++i) {
try {
String clsName = args[i];
Class cls = Class.forName(clsName);
Method meth = cls.getMethod(methodName, signature);
System.out.println("Calling " + methodName + " for " + clsName);
Object obj = cls.newInstance();
Object[] params = new Object[1];
params[0] = new Integer(i);
Object result = meth.invoke(obj, params);
System.out.println("Result: '" + result + "'");
}
catch (ClassNotFoundException e) {
System.out.println("Class not found: " + e);
}
catch (NoSuchMethodException e) {
System.out.println("No such method: " + e);
}
catch (InstantiationException e) {
System.out.println("Cannot instantiate class: " + e);
}
catch (IllegalAccessException e) {
System.out.println("Illegal access: " + e);
}
catch (InvocationTargetException e) {
System.out.println("Bad target for method call: " + e);
}
System.out.println("\n");
}
}
Output of Method Calling Example
$ java ...args... CallMethods left Red Green Blue Calling left for Red Red with Integer 1 Result: 'null' Calling left for Green Green with Integer 2 Result: 'Green string' Calling left for Blue Blue with Integer 3 Result: '99' $ java ...args... CallMethods right Red Green Blue No such method: java.lang.NoSuchMethodException: Red.right(java.lang.Integer) Calling right for Green Green with Integer 2 Result: 'null' No such method: java.lang.NoSuchMethodException: Blue.right(java.lang.Integer)
Switching on Type
Often have to handle basic types case-by-case
For example, an object editor in an IDE
Pattern:
Inspect Object to find out what type it is
Cast it to that type
Do something with integers
Something else with strings
Everything else expressed in terms of these
Doubling Up
Example: double fields of an object without knowing what they are
public static void main(String[] args) {
ObjPoint p = new ObjPoint("center", 3, 3);
System.out.println("Object before doubling: " + p);
doubleField(p, "X");
doubleField(p, "Y");
doubleField(p, "Name");
System.out.println("Object after doubling: " + p);
}
$ java ...args... Double
Object before doubling: [center : 3, 3]
Object after doubling: [centercenter : 6, 6]
Getting the Old Value
public static Object getOldValue(Object obj, String fieldName)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
Class cls = obj.getClass();
String getterName = "get" + fieldName;
Class[] emptyParams = new Class[]{};
Method getter = cls.getMethod(getterName, emptyParams);
Object[] emptyArgs = new Object[]{};
Object oldValue = getter.invoke(obj, emptyArgs);
return oldValue;
}
Setting the New Value
public static void setNewValue(Object obj, String fieldName, Object newValue)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
String setterName = "set" + fieldName;
Class cls = obj.getClass();
Class[] params = new Class[]{newValue.getClass()};
Method setter = cls.getMethod(setterName, params);
Object[] setterArgs = new Object[]{newValue};
setter.invoke(obj, setterArgs);
}
Doubling a Field
Note: this is the only method that needs to be changed to handle more types
public static Object doubleValue(Object original) {
Class cls = original.getClass();
Object result = null;
if (cls == Integer.class) {
int nv = ((Integer)original).intValue() * 2;
result = new Integer(nv);
}
else if (cls == String.class) {
result = ((String)original) + ((String)original);
}
return result;
}
Key Points
There is no magic
A class is just a data structure
A method is just a data structure, too
It just happens to contain bytes that look like instructions for the interpreter
The call stack is another data structure
With libraries to give you access to it at runtime
Many programming tools make use of reflection
We'll see one in the next lecture
$Id: reflect.html,v 1.1.1.1 2004/01/04 05:02:31 reid Exp $