• 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("	");
                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("	");
                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("	");
    
                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
    ", x, y);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
  • 相关阅读:
    安卓学习记录(五)——体温表APP.2
    今日学习
    每日学习
    AS插件快速生成javabean
    LA 5842 Equipment (状态压缩+dp)
    LA 4794 Sharing Chocolate (搜索)
    LA 5844 Leet (dfs 搜索)
    uva 11627 Slalom (二分法)
    ZOJ 3031 Robotruck (dp + 单调队列)
    uva 10012 How Big Is It? (greedy + enumerate)
  • 原文地址:https://www.cnblogs.com/nil2inf/p/4469223.html
Copyright © 2020-2023  润新知