Outline
Other Material
In most languages, introspection begins with an object that represents the class. Typically this object has class Class.
One operation that can be performed with a value of type class is to get its parent class
Class parentClass = aClass.getSuperclass(); // Java
Another operation is to get the list of all subclasses for a class.
aSet <- aClass subclasses " Smalltalk "
You can also get the name of the class as a string
char * name = typeinfo(aVariable).name(); // C++
In some languages, you can take the name of a class (a string) and from this get the class object.
Class aClass = Class.forName("classname"); // Java
The class does not even have to be loaded. The class will automatically be loaded for you.
We have seen already that most languages provide a way to test if an object is an instance of a class
if Member(aVariable, Child) then aChild = Child(aVariable) (* Object Pascal *)
This is needed for downcasting.
However, if you find yourself using this a lot, then you aren't thinking in an object-oriented way, since often such situations can be better written using polymorphism.
The next level of complexity is treating a method as an object.
First step is to get a collection of methods from a class
Method [ ] methods = aClass.getDeclaredMethods(); // Java aSet <- aClass selectors. // SmalltalkIntro OOP, Chapter 25, Slide 06
Using a Method
What can you do with a method object? You can do the usual things of getting its names, argument type signatures, so on.System.out.println(methods[0].getName()); Class c = methods[0].getReturnType();Intro OOP, Chapter 25, Slide 07
Dynamic Execution
You can also invoke the method, passing it the receiver and an array of arguments:Class sc = String.class; Class [ ] paramTypes = new Class[1]; paramTypes[0] = sc; try { Method mt = sc.getMethod("concat", paramTypes); Object mtArgs [ ] = { "xyz" }; Object result = mt.invoke("abc", mtArgs); System.out.println("result is " + result); } catch (Exception e) { System.out.println("Exception " + e); }Here we dynamically look up a method, based both on name and type signature, then create an array of arguments, then execute the method.Intro OOP, Chapter 25, Slide 08
Class Loading
Java has a class named ClassLoader that allows you to define a class from an array of bytes:class SimpleClassLoader extends ClassLoader { public Class getClass (String name) { Class theClass = null; try { File f = new File(name); InputStream is = new FileInputStream(f); int bufsize = (int) f.length(); byte buf [] = new byte[bufsize]; is.read(buf, 0, bufsize); is.close(); theClass = defineClass (null, buf, 0, buf.length); } catch (Exception e) { System.err.println("Error during load " + e); System.exit(1); } return theClass; } }Once you have a class, you can create instances, or execute methods.Intro OOP, Chapter 25, Slide 09
Metaclasses -- Strange Loops
You can get into some interesting places by asking the right questions.
In Java this path circles back on itself very quickly; Class is an intance of itself.
In Smalltalk, the path goes on a bit longer before it circles back on itself.
Remember that by introducing new classes that represent classes, Smalltalk was able to solve the following problem
(For example, the behavior to initialize newly created instances of a class).
The answer was, you don't. You add a new child class that defines the behavior you want, and put this between the object and the true parent.
Relection and Introspection have taken on increasing importance as the field moves from object-based computing to component-based computing (COM, Corba, JavaBeans, etc).
This is because components must often be dynamically loaded and executed. And reflection is the underlying mechanism that permits this.