Algorithm Programming Java Reflection Mechanism Bar-Ilan University תשס"ז Moshe Fresko
RTTI RTTI : Run-time type identification It lets you find the exact type of an object when you have only a reference to the base type “Traditional” RTTI : Assumes that you have all the types available at compile time and run time “Reflection” mechanism : Allows you to discover class information solely at run time.
RTTI – Example in Polymorphism
RTTI - Example class Shape { void draw() { System.out.println(this+".draw()"); } } class Circle extends Shape { public String toString() { return "Circle"; } } class Square extends Shape { public String toString() { return "Square"; } } class Triangle extends Shape { public String toString() { return "Triangle"; } } public class Shapes { public static void main(String[] args) { Object[] shapeList = { new Circle(), new Square(), new Triangle() } ; for(int i = 0; i < shapeList.length; i++) ((Shape)shapeList[i]).draw(); } }
“Class” class The RTTI information is kept in a special object of class “Class”. For each new class in a program a “Class” object is created. Dynamic loading of classes creates a new “Class” object.
Class.forName(…) class Candy { static { System.out.println("Loading Candy"); } } class Gum { static { System.out.println("Loading Gum"); } } class Cookie { static { System.out.println("Loading Cookie"); } } public class SweetShop { public static void main(String[] args) { System.out.println("inside main"); new Candy(); System.out.println("After creating Candy"); try { Class.forName("Gum"); } catch(ClassNotFoundException e) { System.out.println("Couldn't find Gum"); } System.out.println("After Class.forName('Gum')"); new Cookie(); System.out.println("After creating Cookie"); } >java SweetShop inside main Loading Candy After creating Candy Loading Gum After Class.forName(‘Gum’) Loading Cookie After creating Cookie
Casting Type checking on Run time Classic cast can throw ClassCastException “Class” object can be queried for inheritance information “instanceof” keyword Example: if(x instanceof Dog) ((Dog)x).bark();
Creating Instances import java.util.*; class Pet {}class Dog extends Pet {} class Pug extends Dog {}class Cat extends Pet {} class Rodent extends Pet {}class Gerbil extends Rodent {} class Hamster extends Rodent {} public class PetInfo { static Random rand = new Random(); static String[] typenames = { "Pet", "Dog", "Pug", "Cat", "Rodent", "Gerbil", "Hamster" } ; public static void main(String[] args) { Object[] pets = new Object[10]; try { Class[] petTypes = { Class.forName("Dog"), Class.forName("Pug"), Class.forName("Cat"), Class.forName("Rodent"), Class.forName("Gerbil"), Class.forName("Hamster") }; for(int i = 0; i < pets.length; i++) pets[i] = petTypes[rand.nextInt(petTypes.length)].newInstance(); } catch(InstantiationException e) { System.out.println("Cannot instantiate"); System.exit(1); } catch(IllegalAccessException e) { System.out.println("Cannot access"); System.exit(1); } catch(ClassNotFoundException e) { System.out.println("Cannot find class"); System.exit(1); } for(int i = 0; i < pets.length; i++) System.out.println(pets[i].getClass()); } >java PetInfo class Hamster class Gerbil class Cat class Pug class Rodent class Hamster class Dog class Pug class Hamster
“Class” information These two statements can bring the “Class” information. 1. Class c = Class.forName(“Dog”) ; 2. Class c = Dog.class ; The first one throws ClassNotFoundException
Class Instance Of … class Base {} class Derived extends Base {} public class FamilyVsExactType { static void test(Object x) { System.out.println("Testing x of type " + x.getClass()); System.out.println("x instanceof Base " + (x instanceof Base)); System.out.println("x instanceof Derived " + (x instanceof Derived)); System.out.println("Base.isInstance(x) " + Base.class.isInstance(x)); System.out.println("Derived.isInstance(x) " + Derived.class.isInstance(x)); System.out.println("x.getClass() == Base.class " + (x.getClass() == Base.class)); System.out.println("x.getClass() == Derived.class " + (x.getClass() == Derived.class)); System.out.println("x.getClass().equals(Base.class)) "+ (x.getClass().equals(Base.class))); System.out.println("x.getClass().equals(Derived.class)) " + (x.getClass().equals(Derived.class))); } public static void main(String[] args) { test(new Base()); test(new Derived()); } >java FamilyVsExactType Testing x of type class Base x instanceof Base true x instanceof Derived false Base.isInstance(x) true Derived.isInstance(x) false x.getClass() == Base.class true x.getClass() == Derived.class false x.getClass().equals(Base.class)) true x.getClass().equals(Derived.class)) false Testing x of type class Derived x instanceof Base true x instanceof Derived true Base.isInstance(x) true Derived.isInstance(x) true x.getClass() == Base.class false x.getClass() == Derived.class true x.getClass().equals(Base.class)) false x.getClass().equals(Derived.class)) true
RTTI syntax interface HasBatteries {} interface Waterproof {} interface Shoots {} class Toy { Toy() {} Toy(int i) {} } class FancyToy extends Toy implements HasBatteries, Waterproof, Shoots { FancyToy() { super(1); } } public class ToyTest { static void printInfo(Class cc) { System.out.println("Class: " + cc.getName() + " is interface? “ + cc.isInterface() ); } public static void main(String[] args) { Class c = null; try { c = Class.forName("FancyToy"); } catch(ClassNotFoundException e) { System.out.println("Can't find FancyToy"); System.exit(1); } printInfo(c); Class[] faces = c.getInterfaces(); for(int i = 0; i < faces.length; i++) printInfo(faces[i]); Class cy = c.getSuperclass(); Object o = null; try { o = cy.newInstance(); // Requires default constructor: } catch(InstantiationException e) { System.out.println("Cannot instantiate"); System.exit(1); } catch(IllegalAccessException e) { System.out.println("Cannot access"); System.exit(1); } printInfo(o.getClass()); } >java ToyTest Class: FancyToy is interface? false Class: HasBatteries is interface? true Class: Waterproof is interface? true Class: Shoots is interface? true Class: Toy is interface? false
Reflection mechanism With “RTTI” we can access class information that is known at compile time. With “Reflection” we can access classes that was not known previously to compiler. “Class” supports reflection java.lang.reflect.* : “Member” interface “Field” class “Method” class “Constructor” class
Reflection Retrieving class objects Class c1 = myinst.getClass() ; Class c2 = c1.getSuperclass() ;// can return null Class c3 = Button.class ; Class c4 = Class.forName(mystring) ; Getting the class name String s = c1.getName() ; Getting the class modifiers int m = c1.getModifiers() ; bool isPublic = Modifier.isPublic(m) ; bool isAbstract = Modifier.isAbstract(m) ; bool isFinal = Modifier.isFinal(m) ;
Reflection Getting the interfaces implemented by a class Class c = myinst.getClass() ; Class [ ] itfs = c.getInterfaces() ; Examining interfaces bool isInterface = myClass.isInterface() ; Identifying class fields Field [ ] publicFields = c.getFields() ; for (int i=0;i<publicFields.length;++i) { String fieldName = publicFields[i].getName() ; Class typeClass = publicFields[i].getType() ; … }
Reflection Discovering Class Constructors Class c = myinst.getClass() ; Constructor [ ] ctors = c.getConstructors() ; for (int i=0;i<ctors.length;++i) { Class [ ] params = ctors[i].getParameterTypes() ; for (int k=0;k<params.length;++k) { String paramType = params[k].getName() ; … }
Reflection Getting Method Information Class c = myinst.getClass() ; Method [ ] ms = c.getMethods() ; for (int i=0;i<ms.length;++i) { String mname = ms[i].getName() ; Class retType = ms[i].getReturnType() ; Class[] params = ms[i].getParameterTypes() ; for (int k=0;k<params.length;++k) { String paramType = params[k].getName() ; … }
Reflection – Creating Objects Using Default Constructors Class c = Class.forName(“java.awt.Rectangle”) ; Rectangle r = (Rectangle) c.newInstance() ; Using Constructors with Arguments Class c = Class.forName(“java.awt.Rectangle”) ; Class[] intArgsClass = new Class[]{ int.class, int.class } ; Object[] intArgs = new Object[]{new Integer(12),new Integer(24)} ; Constructor ctor = c.getConstructor(intArgsClass) ; Rectangle r = (Rectangle) ctor.newInstance(intArgs) ;
Reflection – Accessing Fields Getting Field Values Rectangle r = new Rectangle(12,24) ; Class c = r.getClass() ; Field f = c.getField(“height”) ; Integer h = (Integer) f.get(r) ; Setting Field Values Rectangle r = new Rectangle(12,24) ; Class c = r.getClass() ; Field f = c.getField(“width”) ; f.set(r,new Integer(30)) ;
Reflection – Invoking Methods String s1 = “Hello ” ; String s2 = “World” ; Class c = String.class ; Class[] paramtypes = new Class[] { String.class } ; Object[] args = new Object[] { s2 } ; Method concatMethod = c.getMethod(“concat”,paramtypes) ; String result = (String) concatMethod.invoke(s1,args) ;
Tips Don’t use the reflection API when other tools more natural to Java are enough for a specific problem. It is easier to debug and maintain a program if you don’t use Reflection objects.