Core Java笔记 3.反射

本章重点:

  • Class 类
  • 利用反射分析类
  • 在运行时使用反射分析对象
  • 使用反射编写泛型数组代码
  • 方法指针

能够分析类能力的程序称为反射(reflective). Java 提供了丰富且精心设计的工具集(reflection library).

Class 类

在程序运行期间,Java 运行时系统始终为所有的对象维护着一个运行时的类型标识,这个信息保存着每个对象所属的类足迹.

获取 Class 实例.

// 1. 通过实例获得.
Employee e;
Class cl = e.getClass();

// 2. 通过类名获得.
String className = "java.util.Date";
Class cl = Class.forName(className); // need try...catch

// 3. 通过类获得.
Class cl = Date.class
Class cl = int.class

虚拟机为每个类型管理一个Class对象.

if (e.getClass = Employee.class) ...

通过 Class 创建实例.

e.getClass().newInstance();   // 需要有无参构造器
Date.getClass().newInstance();
Class.forName("xxx").newInstance();

利用反射分析类

java.lang.reflect包中的三个核心类: Field、Method、Constructor.

使用反射分析类

package corejava.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Scanner;

/**
 * Created by guolong.fan on 15/4/24.
 */
public class ReflectionTest {

    public static void main(String[] args) {
        String name;
        if (args.length > 0) name = args[0];
        else {
            Scanner in = new Scanner(System.in);
            System.out.println("Enter class name(e.g. java.util.Date):");
            name = in.next();
        }

        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.println(" {");
            printConstructors(cl);
            System.out.println();
            printMethods(cl);
            System.out.println();
            printFields(cl);
            System.out.println("}");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static void printConstructors(Class cl) {
        Constructor[] constructors = cl.getDeclaredConstructors();
        for (Constructor c : constructors) {
            String name = c.getName();
            System.out.print("\t");
            String modifiers = Modifier.toString(c.getModifiers());
            if (modifiers.length() > 0) System.out.print(modifiers + " ");
            System.out.print(name + "(");
            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.print(")");
            Class[] expTypes = c.getExceptionTypes();
            if (expTypes.length > 0) System.out.print(" throws ");
            for (int j = 0; j < expTypes.length; ++j) {
                if (j > 0) System.out.print(", ");
                System.out.print(expTypes[j].getName());
            }
            System.out.println(";");
        }
    }

    private static void printMethods(Class cl) {
        Method[] methods = cl.getDeclaredMethods();
        for (Method m : methods) {
            String name = cl.getName();
            Class refType = m.getReturnType();

            System.out.print("\t");
            String modifiers = Modifier.toString(m.getModifiers());
            if (modifiers.length() > 0) System.out.print(modifiers + " ");
            System.out.print(refType.getName() + " ");
            System.out.print(name + "(");
            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.print(")");

            Class[] expTypes = m.getExceptionTypes();
            if (expTypes.length > 0) System.out.print(" throws ");
            for (int j = 0; j < expTypes.length; ++j) {
                if (j > 0) System.out.print(", ");
                System.out.print(expTypes[j].getName());
            }
            System.out.println(";");
        }
    }

    private static void printFields(Class cl) {
        Field[] fields = cl.getDeclaredFields();
        for (Field f : fields) {
            String name = f.getName();
            Class type = f.getType();

            String modifiers = Modifier.toString(f.getModifiers());
            System.out.print("\t");

            if (modifiers.length() > 0) System.out.print(modifiers + " ");
            System.out.println(type.getName() + " " + name + ";");
        }
    }

}

在运行时使用反射分析对象

实现通用的toString.

package corejava.reflection;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by guolong.fan on 15/4/24.
 */
public class ObjectAnalyzer {

    /**
     * Converts an object to a string representation that lists all fields.
     * @param obj an object
     * @return a string with the obejct's class name and all fields name and
     * values
     */
    public String toString(Object obj) {
        if (obj == null) return "null";
        if (visited.contains(obj)) return "...";
        visited.add(obj);

        Class cl = obj.getClass();
        if (cl == String.class) return (String)obj;
        if (cl.isArray()) {
            String r = cl.getComponentType() + "[]{";
            for (int i = 0; i < Array.getLength(obj); ++i) {
                if (i > 0) r += ",";
                Object val = Array.get(obj, i);
                if (cl.getComponentType().isPrimitive()) r += val;
                else r += toString(val);

            }
            return r + "}";
        }

        String r = cl.getName();

        // inspect the fields of this class and all superclasses
        do {
            r += "[";
            Field[] fields = cl.getDeclaredFields();
            AccessibleObject.setAccessible(fields, true);

            for (Field f : fields) {
                if (!Modifier.isStatic(f.getModifiers())) {
                    if (!r.endsWith("[")) r += ",";
                    r += f.getName() + "=";
                    try {
                        Class t = f.getType();
                        Object val = f.get(obj);
                        if (t.isPrimitive()) r += val;
                        else r += toString(val);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            r += "]";
            cl = cl.getSuperclass();
        } while (cl != null);

        return r;
    }

    private List<Object> visited = new ArrayList<Object>();

    public static void main(String[] args) {
        ArrayList<Integer> squares = new ArrayList<Integer>();
        for (int i = 0; i < 5; ++i) {
            squares.add(i * i);
        }
        System.out.println(new ObjectAnalyzer().toString(squares));
        System.out.println(squares);
    }
}

使用反射编写泛型数组代码

package corejava.reflection;

import java.lang.reflect.Array;

/**
 * Created by guolong.fan on 15/4/24.
 */
public class ArrayGrowTest {

    public static void main(String[] args) {
        int[] a = { 1, 2, 3 };
        a = (int[])goodArrayGrow(a);

        String[] b = { "Tom", "Dick", "Harry" };
        b = (String[]) goodArrayGrow(b);

        // Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
        // at corejava.reflection.ArrayGrowTest.main(ArrayGrowTest.java:10)
        System.out.println("The following call will generate an exception.");
        b = (String[])badArrayGrow(b);

        // 要理解这些,需要把泛型数组看成一种类型。Integer[] 和 Object[] 不是一种类型!!!
        // 有自己的 Class 对象!!!
        Integer[] intArr = new Integer[10];
        Object[] objArr = intArr;  // OK

        // Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
        // at corejava.reflection.ArrayGrowTest.main(ArrayGrowTest.java:20)
        Object[] objArr2 = new Object[10];
        Integer[] intArr2 = (Integer[])objArr2; // Exception
    }

    /**
     * This method attempts to grow an array by alocating a new array and copying all elements.
     * @param a the array to grow
     * @return a larger array that contains all elements of a. However, the returned array has
     * type Object[], not the same type as a.
     */
    static Object[] badArrayGrow(Object[] a) {
        int newLength = a.length * 11 / 10 + 10;
        Object[] newArray = new Object[newLength];
        System.arraycopy(a, 0, newArray, 0, a.length);
        return newArray; // newArray is Object[], not the same type as a.
    }

    /**
     * This method grows an array by allocating a new array of the same type and
     * copying all elements.
     * @param a the array to grow. This can be an object array or a primitive
     *          type array
     * @return a larger array that contains all elements of a.
     */
    static Object goodArrayGrow(Object a) {
        if (a == null) return null;

        Class cl = a.getClass();
        if (!cl.isArray()) return null;

        Class componentType = cl.getComponentType();
        int length = Array.getLength(a);  // 获取a的类型
        int newLength = length * 11 / 10 + 10;

        Object newArray = Array.newInstance(componentType, newLength); // newArray is the same type as a!!
        System.arraycopy(a, 0, newArray, 0, length);
        return newArray;
    }

}

方法指针

Java 没有提供方法指针,但是利用反射可以实现方法指针,但是从设计角度来说,方法指针会来带隐患. interface 是更好的解决方案.

Method m1 = Employee.class.getMethod("getName");
Method m2 = Employee.class.getMethod("raiseSalary", double.class);

Employee e = new Employee();
m1.invoke(e);
m2.invoke(e, 1.0);

示例:

package corejava.reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by guolong.fan on 15/4/24.
 */
public class MethodPointerTest {

    public static void main(String[] args) throws NoSuchMethodException {
        Method square = MethodPointerTest.class.getMethod("squre", double.class);
        printTable(1, 10, 10, square);
    }

    public static double squre(double x) {
        return x * x;
    }

    private static void printTable(double from, double to, int n, Method 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 (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}
posted @ 2015-04-30 16:24  nil2inf  阅读(294)  评论(0编辑  收藏  举报