Reflection
- Run-time access to the types and structure of a program.
- e.g., programmatic access to a class’s variables and methods.
- Used by IDE’s and debuggers
- Also used by JUnit.
Java Reflection
- “Class” class describes a class’s variables and methods.
- (yes, the name is awkward.)
- Look at JavaDoc.
- There is a
Field
class describing fields. - There is a
Method
class describing methods - Can query methods, like the presence of Annotations.
Method
class has aninvoke
method that allows you to invoke an arbitrary method on an object.- (Although, you loose the benefits of static type checking.)
- There is a
- This is how
JUnit
works:- Take class under test.
- Iterate through methods.
- Check for
@Test
annotation - If present, invoke the method.
- You can use reflection to do “illegal” things like invoke private methods.
Ruby reflection
- Call
String.print_methods
- Call method using name in a string:
"abcde".send("reverse".to_sym)
- This means you could ask the user to type in the name of a method, then execute it without an else-if chain!
method_missing
class String
def method_missing(name, p1)
self + " #{name} --- #{p1}"
end
end
puts "abcde".bob_the_great('more stuff')
One use: Make a Hash behave like an object:
class Hash
def method_missing(name)
if self.has_key?(name)
return self[name]
end
end
end
h = {a:1, b:2, c:3, d:4}
p h.a
p h.e
Java Reflection Example
import java.lang.reflect.*;
import java.lang.annotation.*;
import java.util.*;
class Reflection {
@Retention(RetentionPolicy.RUNTIME)
@interface MyTest {
String name() default "<NoName>";
}
public void method1(int a, int b) {
System.out.println(a + b);
}
public String method2(String a, float b ) {
return a + b;
}
@MyTest
public void testMethod1() {
System.out.println("Running test method 1");
}
@MyTest(name = "Bob the Test Method")
public void testMethod2() {
System.out.println("Running test method 2");
}
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException {
List<Method> testMethods = new ArrayList<>();
for (Method m : Reflection.class.getDeclaredMethods()) {
System.out.println(m);
for (Annotation a: m.getAnnotations()) {
System.out.println("\t" + a);
if (a.annotationType().equals(MyTest.class)) {
testMethods.add(m);
}
}
}
System.out.println("Running test methods:");
for (Method m : testMethods) {
m.invoke(new Reflection());
}
}
}