Java Reflection

来源:互联网 发布:3d360度全景图制作知乎 编辑:程序博客网 时间:2024/06/05 23:04

1 Reflection

A program that can analyze the capabilities of classes is called reflective.
The reflection mechanism is extremely powerful to

  • Analyze the capabilities of classes at runtime;
  • Inspect objects at runtime;
  • Implement generic array manipulation code;
  • Take advantage of Method objects that work just like function pointers in languages such as C++.

2 The Class Class

The Java runtime system always maintains runtime type identifcation on all objects.
You can access this information by working with a special Java class called Class.
The virtual machine manages a unique Class object for each type.
注意区分:a Class object 和 an object of a class

a Class object 是一个 Class 类的对象
an object of a class 是一个普通类的对象,或者直接叫做 an object

Three methods for obtaining a Class object

//the getClass() of ObjectEmployee e;Class cl = e.getClass();
//the static forName method using a class name for parameterString className = "java.util.Random";Class cl = Class.forName(className);
//If T is any Java type, then T.class is the matching class object.Class cl1 = Random.class; Class cl2 = int.class;Class cl3 = Double[].class;Class cl3 = void.class;

The getName method of Class returns the name of a Class object

System.out.println(int.class.getName()); //intSystem.out.println(int[].class.getName()); //[I ,Integer 数组System.out.println(e.getClass().getName()); //application.Employee ,全类名try {    Class cl = Class.forName("java.util.Random");    System.out.println(cl.getName()); //java.util.Random} catch (ClassNotFoundException e) {                    e.printStackTrace();}

The newInstance() of Class helps you create an object of a class on the fly.
The newInstance method calls the no-argument constructor to initialize the newly created object.
An exception is thrown if the class does not have a no-argument constructor.
forName and newInstance lets you create an object from a class name stored in a string

String s = "java.util.Random";Object m = Class.forName(s).newInstance();

3 Analyze the Capabilities of Classes

The getFields methods of the Class class returns an array of the public felds that the class supports, including public members of superclasses.
And the getMethods returns an array of the public methods.
And the getConstructors returns an array of the public constructors .

The getDeclaredFields method of the Class class returns an array consisting of all felds that are declared in the class including private, package, and protected members, but not members of superclasses.
The getDeclaredMethods and the getDeclaredConstructors works similarly

java.lang.reflect.Field : describe the felds of a class
java.lang.reflect.Method : describe the methods of a class
java.lang.reflect.Constructor : describe the constructors of a class
java.lang.reflect.Modifier : describe the modifiers of a class

The ClassAnalyzer class uses reflection to print all features of a given class

import java.lang.reflect.*;public class ClassAnalyzer {    public static void printClass(String name) {        try {            // print class name and superclass name (if != Object)            Class cl = Class.forName(name);            Class supercl = cl.getSuperclass();            String modifiers = Modifier.toString(cl.getModifiers());            if (modifiers.length() > 0)                System.out.print(modifiers + " ");            System.out.print("class " + name);            if (supercl != null && supercl != Object.class)                System.out.print(" extends " + supercl.getName());            System.out.print("{\n");            printConstructors(cl);            System.out.println();            printMethods(cl);            System.out.println();            printFields(cl);            System.out.println("}");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        System.exit(0);    }    public static void printConstructors(Class cl) {        Constructor[] constructors = cl.getDeclaredConstructors();        for (Constructor c : constructors) {            String name = c.getName();            System.out.print("   ");            String modifiers = Modifier.toString(c.getModifiers());            if (modifiers.length() > 0)                System.out.print(modifiers + " ");            System.out.print(name + "(");            // print parameter types            Class[] paramTypes = c.getParameterTypes();            for (int j = 0; j < paramTypes.length; j++) {                if (j > 0)                    System.out.print(", ");                System.out.print(paramTypes[j].getName());            }            System.out.println(");");        }    }    public static void printMethods(Class cl) {        Method[] methods = cl.getDeclaredMethods();        for (Method m : methods) {            Class retType = m.getReturnType();            String name = m.getName();            System.out.print("   ");            // print modifiers, return type and method name            String modifiers = Modifier.toString(m.getModifiers());            if (modifiers.length() > 0)                System.out.print(modifiers + " ");            System.out.print(retType.getName() + " " + name + "(");            // print parameter types            Class[] paramTypes = m.getParameterTypes();            for (int j = 0; j < paramTypes.length; j++) {                if (j > 0)                    System.out.print(", ");                System.out.print(paramTypes[j].getName());            }            System.out.println(");");        }    }    public static void printFields(Class cl) {        Field[] fields = cl.getDeclaredFields();        for (Field f : fields) {            Class type = f.getType();            String name = f.getName();            System.out.print("   ");            String modifiers = Modifier.toString(f.getModifiers());            if (modifiers.length() > 0)                System.out.print(modifiers + " ");            System.out.println(type.getName() + " " + name + ";");        }    }}

4 Analyze Objects at Runtime

Reflection lets you look at felds of objects that were not known at compile time.
The key method to achieve this is the get method in the Field class.
f.get(obj) returns an object whose value is the current value of the field of obj.
You can only use get to get the values of accessible felds.
To override this access control, you can invoke the setAccessible method on a Field, Method, or Constructor object.

Employee harry = new Employee("Harry", 35000, 10, 1, 1989);Class cl = harry.getClass();Field f = cl.getDeclaredField("name");// the name fieldf.setAccessible(true); // now OK to call f.get(harry);Object v = f.get(harry);// the value of the name field

Of course, you can also set the values that you can get.
The call f.set(obj, value) sets the field represented by f of the object obj to the new value.

5 Invoking Arbitrary Methods

The reflection mechanism allows you to call arbitrary methods.
Firstly, you can call the getMethod method of the Class class to obtain a Method object.

Method getMethod(String name, Class... parameterTypes)

Then, the Method class has an invoke method that lets you call the method that is wrapped in the current Method object.

Object invoke(Object obj, Object... args)

For a static method, the first parameter is ignored—you can set it to null.
Also, the parameters and return values of invoke are necessarily of type Object.
That means you must cast back and forth a lot.

double y = (Double) f.invoke(null, x);

This program shows how to invoke methods through reflection

public class MethodInvoker {    public static void main(String[] args) throws Exception {        Method square = MethodInvoker.class.getMethod("square", double.class);        Method sqrt = Math.class.getMethod("sqrt", double.class);               printTable(1, 10, 10, square);        printTable(1, 10, 10, sqrt);    }    public static double square(double x) {        return x * x;    }       public static void printTable(double from, double to, int n, Method f) {        // print out the method as table header        System.out.println(f);        double dx = (to - from) / (n - 1);        for (double x = from; x <= to; x += dx) {            try {                double y = (Double) f.invoke(null, x);                System.out.printf("%10.4f | %10.4f%n", x, y);            } catch (Exception e) {                e.printStackTrace();            }        }    }}

6 Do not overuse reflection

The reflection mechanism lets you write programs with amazing generality, by detecting fields and methods at runtime.
This capability can be extremely useful for systems programming, but it is usually not appropriate in applications.
Reflection is fragile—with it, the compiler cannot help you find programming errors.
Any errors are found at runtime and result in exceptions.

原创粉丝点击