ReflectUitls类的编写和对反射机制的解析

来源:互联网 发布:mac系统怎么安装 编辑:程序博客网 时间:2024/06/05 16:38

反射相关的类

  反射相关的类,最基本的当然是Class类。

  获取了Class对象之后,就可以接着生成对象实例、调用方法、查看字段等等。

  字段(Field)、方法(Method)和构造方法(Constructor<T>)各有相应的类来表示,它们共同继承于java.lang.reflect.AccessibleObject类:

 

 

  这三个类共同实现的还有Member接口:

 

 

  获取字段、方法和构造方法时,需要调用Class类的getXXX()getDeclearedXXX()方法,需要注意二者区别。

  比如对于方法:

getMethods();//获取public (包括父类中的)getDeclaredMethods();//获取本类声明(包括各种修饰符public、private)

 

  相关博文:Java中的反射机制(一)

  API 文档:http://docs.oracle.com/javase/7/docs/api/

 

访问权限相关

  利用反射,可以访问一些SDK、API中的私有方法。

  相关博文:Java中的反射机制(四) 利用反射访问私有

 

  访问私有方法有一个关键点:

setAccessible(true); // 抑制Java对修饰符的检查

  这个方法是AccessibleObject类中的。

  前面说过,它是FieldMethodConstructor<T>的共同基类。

 

  正常情况下,调用isAccessible()返回的都是false,无论你的方法是public还是private。

  这是因为这个accessible的flag是JVM用来限制是否可以直接访问,默认情况下是需要进行访问修饰符的检查的,所以flag为false,即不能直接访问。

  当这个flag设置为true,表明可以直接访问,不经过访问修饰符的检查

 

  辅助类中用于调用私有方法的接口:

复制代码
/**     * 调用私有方法     *     * @param obj     *            调用类对象     * @param methodName     *            方法名     * @param paramTypes     *            参数类型     * @param params     *            参数     * @return     * @throws Exception     */    public static Object invokePrivateMethod(Object obj, String methodName,            Class<?>[] paramTypes, Object[] params) throws Exception {        Object value = null;        Class<?> cls = obj.getClass();        // 注意不要用getMethod(),因为getMethod()返回的都是public方法        Method method = cls.getDeclaredMethod(methodName, paramTypes);        method.setAccessible(true);// 抑制Java的访问控制检查        value = method.invoke(obj, params);        return value;    }
复制代码

 

访问修饰符

  对访问修饰符的获取可以通过Member接口的getModifiers()方法,该方法返回一个整型值,整型值是一系列的修饰符位操作组合的结果。

  用Modifier类可以解析这个整型值中包含的修饰符信息。

复制代码
    /**     * 获取修饰符信息     *     * @param member     * @return     */    private static String getModifiersInfo(Member member) {        StringBuilder sBuilder = new StringBuilder();        int modifiers = member.getModifiers();        sBuilder.append("\ngetModifiers: " + +modifiers + ", ");// 得到修饰符编码        sBuilder.append("\nisPublic: " + Modifier.isPublic(modifiers) + ", ");        sBuilder.append("\nisPrivate: " + Modifier.isPrivate(modifiers) + ", ");        sBuilder.append("\nisStatic: " + Modifier.isStatic(modifiers) + ", ");        sBuilder.append("\nisFinal: " + Modifier.isFinal(modifiers) + ", ");        sBuilder.append("\nisAbstract: " + Modifier.isAbstract(modifiers));        return sBuilder.toString();    }
复制代码

 

包装类与原生数据类型

  相关博文: Java 包装类 自动装箱和拆箱

  写了一个调用静态方法的辅助类,我本来是这么写的:

复制代码
    /*     * wrong:     * public static Object invokePublicStaticMethod(String className,     * String methodName, Object[] params) throws Exception {     *     * Class<?> cls = Class.forName(className);     * Class<?>[] paramTypes = new Class<?>[params.length];     * for (int i = 0; i < params.length; ++i) {     * paramTypes[i] = params[i].getClass();     *     * }     * Method method = cls.getMethod(methodName, paramTypes);     * Object value = null;     * if (isPublicStatic(method)) {     * value = method.invoke(null, params);     * }     *     * return value;     * }     */
复制代码

  意图是只传入参数数组,在内部自己根据参数获取类型数组,可以少传点参数,但是这样遇到了问题。

 

  在Example类里写了这么三个测试方法:

复制代码
    public static void printSomething(String line) {        System.out.println(line);    }    public static int add(int a, int b) {        return a + b;    }    public static double getPi() {        return 3.14159d;    }
复制代码

 

  测试的时候发现参数是String类型的时候可以正常执行,但是参数如果是原生数据类型(int类型),用这个方法调用时就跑出了异常:

  java.lang.NoSuchMethodException: com.mengdd.reflect.Example.add(java.lang.Integer, java.lang.Integer)

  

  测试了一下:

Object[] array = new Object[] { 1, 2 };System.out.println("getClass(): " + array[0].getClass());System.out.println("Integer.TYPE: " + Integer.TYPE);

  输出:

getClass(): class java.lang.IntegerInteger.TYPE: int

  而那个用于测试的add()方法:

getReturnType: intgetParameterTypes: [int, int]

  可见Integerint被认为是两种类型,所以调用方法的时候,类型参数也还是从外部传入比较科学。

 

  修改后的调用方法如下:

复制代码
    public static Object invokePublicStaticMethod(String className,            String methodName, Class<?>[] paramTypes, Object[] params)            throws Exception {        Class<?> cls = Class.forName(className);        Method method = cls.getMethod(methodName, paramTypes);        Object value = null;        if (isPublicStatic(method)) {            value = method.invoke(null, params);        }        return value;    }
复制代码

  测试代码:

 

复制代码
            Object result1 = ReflectUtils.invokePublicStaticMethod(                    "com.mengdd.reflect.Example", "add", new Class<?>[] {                            int.class, Integer.TYPE }, new Object[] { 1, 2 });            // int.class和Integer.TYPE都行            Assert.assertEquals(3, result1);
复制代码

 

 

ReflectUtils类

  ReflectUtils类完整代码如下:

复制代码
package com.mengdd.reflect;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Member;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.util.Arrays;/** * * @ClassName ReflectUtils * @Description Reflection Helper class * * @author mengdandan * @Date 2014年5月13日上午10:40:32 * */public class ReflectUtils {    /**     * 创建类的实例,调用类的无参构造方法     *     * @param className     * @return     */    public static Object newInstance(String className) {        Object instance = null;        try {            Class<?> clazz = Class.forName(className);            instance = clazz.newInstance();        }        catch (ClassNotFoundException e) {            e.printStackTrace();        }        catch (InstantiationException e) {            // if this Class represents an abstract class, an interface, an            // array class, a primitive type, or void; or if the class has no            // nullary constructor; or if the instantiation fails for some other            // reason.            e.printStackTrace();        }        catch (IllegalAccessException e) {            // if the class or its nullary constructor is not accessible            e.printStackTrace();        }        return instance;    }    /**     * 获取所有的public构造方法的信息     *     * @param className     * @return     */    public static String getPublicConstructorInfo(String className) {        StringBuilder sBuilder = new StringBuilder();        try {            Class<?> clazz = Class.forName(className);            Constructor<?>[] constructors = clazz.getConstructors();            sBuilder.append(getConstructorInfo(constructors));        }        catch (ClassNotFoundException e) {            e.printStackTrace();        }        return sBuilder.toString();    }    /**     * 得到本类内声明的构造方法信息     *     * @param className     * @return     */    public static String getDeclearedConstructorInfo(String className) {        StringBuilder sBuilder = new StringBuilder();        try {            Class<?> clazz = Class.forName(className);            Constructor<?>[] constructors = clazz.getDeclaredConstructors();            sBuilder.append(getConstructorInfo(constructors));        }        catch (ClassNotFoundException e) {            e.printStackTrace();        }        return sBuilder.toString();    }    /**     * 获取public的字段信息     *     * @param className     * @return     */    public static String getPublicFieldInfo(String className) {        StringBuilder sBuilder = new StringBuilder();        try {            Class<?> clazz = Class.forName(className);            Field[] fields = clazz.getFields();            sBuilder.append(getFieldInfo(fields));        }        catch (ClassNotFoundException e) {            e.printStackTrace();        }        return sBuilder.toString();    }    /**     * 获取本类内声明的字段信息     *     * @param className     * @return     */    public static String getDecleardFieldInfo(String className) {        StringBuilder sBuilder = new StringBuilder();        try {            Class<?> clazz = Class.forName(className);            Field[] fields = clazz.getDeclaredFields();            sBuilder.append(getFieldInfo(fields));        }        catch (ClassNotFoundException e) {            e.printStackTrace();        }        return sBuilder.toString();    }    /**     * 得到所有public方法信息     *     * @param className     * @return     */    public static String getPublicMethodInfos(String className) {        StringBuilder sBuilder = new StringBuilder();        try {            Class<?> clazz = Class.forName(className);            Method[] methods = clazz.getMethods();// 得到所有的public方法,包括从基类继承的            sBuilder.append(getMethodInfo(methods));        }        catch (ClassNotFoundException e) {            e.printStackTrace();        }        return sBuilder.toString();    }    /**     * 得到类内声明的方法信息     *     * @param className     * @return     */    public static String getDeclaredMethodInfos(String className) {        StringBuilder sBuilder = new StringBuilder();        try {            Class<?> clazz = Class.forName(className);            Method[] methods = clazz.getDeclaredMethods();// 得到本类声明的所有方法,包括私有方法            // clazz.getMethods(); 会返回所有public的方法,但是包括基类Object的方法            sBuilder.append(getMethodInfo(methods));        }        catch (ClassNotFoundException e) {            e.printStackTrace();        }        catch (Exception e) {            e.printStackTrace();        }        return sBuilder.toString();    }    /**     * 得到构造器信息     *     * @param constructor     * @return     */    private static String getConstructorInfo(Constructor<?> constructor) {        StringBuilder sBuilder = new StringBuilder();        sBuilder.append("name: " + constructor.getName());        sBuilder.append("\ngetParameterTypes: "                + Arrays.toString(constructor.getParameterTypes()));        return sBuilder.toString();    }    /**     * 将一组构造器的信息组成一个字符串返回     *     * @param constructors     * @return     */    private static String getConstructorInfo(Constructor<?>[] constructors) {        StringBuilder sBuilder = new StringBuilder();        int i = 0;        for (Constructor<?> c : constructors) {            sBuilder.append("method: " + ++i + " : ");            sBuilder.append("\n" + getConstructorInfo(c));            sBuilder.append("\n");        }        return sBuilder.toString();    }    /**     * 获取字段信息,组成一个字符串返回     *     * @param field     * @return     */    private static String getFieldInfo(Field field) {        StringBuilder sBuilder = new StringBuilder();        sBuilder.append("name: " + field.getName());        sBuilder.append("\ngetType: " + field.getType());        sBuilder.append(getModifiersInfo(field));        return sBuilder.toString();    }    /**     * 获取一组字段的信息,返回字符串     *     * @param fields     * @return     */    private static String getFieldInfo(Field[] fields) {        StringBuilder sBuilder = new StringBuilder();        int i = 0;        for (Field field : fields) {            sBuilder.append("field: " + ++i + " : ");            sBuilder.append("\n" + getFieldInfo(field));            sBuilder.append("\n");        }        return sBuilder.toString();    }    /**     * 获取方法的信息,组成一个字符串返回     *     * @param method     * @return     */    private static String getMethodInfo(Method method) {        StringBuilder sBuilder = new StringBuilder();        sBuilder.append("name: " + method.getName());        sBuilder.append("\ngetReturnType: " + method.getReturnType());        sBuilder.append("\ngetParameterTypes: "                + Arrays.toString(method.getParameterTypes()));        sBuilder.append(getModifiersInfo(method));        return sBuilder.toString();    }    /**     * 获取一组方法的信息,组成一个字符串返回     *     * @param methods     * @return     */    private static String getMethodInfo(Method[] methods) {        StringBuilder sBuilder = new StringBuilder();        int i = 0;        for (Method method : methods) {            sBuilder.append("method: " + ++i + " : ");            sBuilder.append("\n" + getMethodInfo(method));            sBuilder.append("\n");        }        return sBuilder.toString();    }    /**     * 获取修饰符信息     *     * @param member     * @return     */    private static String getModifiersInfo(Member member) {        StringBuilder sBuilder = new StringBuilder();        int modifiers = member.getModifiers();        sBuilder.append("\ngetModifiers: " + +modifiers + ", ");// 得到修饰符编码        sBuilder.append("\nisPublic: " + Modifier.isPublic(modifiers) + ", ");        sBuilder.append("\nisPrivate: " + Modifier.isPrivate(modifiers) + ", ");        sBuilder.append("\nisStatic: " + Modifier.isStatic(modifiers) + ", ");        sBuilder.append("\nisFinal: " + Modifier.isFinal(modifiers) + ", ");        sBuilder.append("\nisAbstract: " + Modifier.isAbstract(modifiers));        return sBuilder.toString();    }    /**     * 是否是公用静态方法     *     * @param member     * @return     */    private static boolean isPublicStatic(Member member) {        boolean isPS = false;        int mod = member.getModifiers();        isPS = Modifier.isPublic(mod) && Modifier.isStatic(mod);        return isPS;    }    /**     * 调用静态方法     *     * @param className     * @param methodName     * @param paramTypes     * @param params     * @return     * @throws Exception     */    public static Object invokePublicStaticMethod(String className,            String methodName, Class<?>[] paramTypes, Object[] params)            throws Exception {        Class<?> cls = Class.forName(className);        Method method = cls.getMethod(methodName, paramTypes);        Object value = null;        if (isPublicStatic(method)) {            value = method.invoke(null, params);        }        return value;    }    /*     * wrong:     * public static Object invokePublicStaticMethod(String className,     * String methodName, Object[] params) throws Exception {     *     * Class<?> cls = Class.forName(className);     * Class<?>[] paramTypes = new Class<?>[params.length];     * for (int i = 0; i < params.length; ++i) {     * paramTypes[i] = params[i].getClass();     *     * }     * Method method = cls.getMethod(methodName, paramTypes);     * Object value = null;     * if (isPublicStatic(method)) {     * value = method.invoke(null, params);     * }     *     * return value;     * }     */    /**     * 调用私有方法     *     * @param obj     *            调用类对象     * @param methodName     *            方法名     * @param paramTypes     *            参数类型     * @param params     *            参数     * @return     * @throws Exception     */    public static Object invokePrivateMethod(Object obj, String methodName,            Class<?>[] paramTypes, Object[] params) throws Exception {        Object value = null;        Class<?> cls = obj.getClass();        // 注意不要用getMethod(),因为getMethod()返回的都是public方法        Method method = cls.getDeclaredMethod(methodName, paramTypes);        method.setAccessible(true);// 抑制Java的访问控制检查        value = method.invoke(obj, params);        return value;    }}
复制代码

 

  测试类和测试代码:

复制代码
package com.mengdd.reflect;public class Example {    private String mFiledOne = null;    private int mCount = 0;    private double mNum = 6;    public int mPub = 4;    public Example() {    }    public Example(String filedOne, int count, double num) {        super();        this.mFiledOne = filedOne;        this.mCount = count;        this.mNum = num;    }    public String getFiledOne() {        return mFiledOne;    }    public void setFiledOne(String filedOne) {        this.mFiledOne = filedOne;    }    public int getCount() {        return mCount;    }    public void setCount(int count) {        this.mCount = count;    }    public double getNum() {        return mNum;    }    public void setNum(double num) {        this.mNum = num;    }    public static void printSomething(String line) {        System.out.println(line);    }    public static int add(int a, int b) {        return a + b;    }    public static double getPi() {        return 3.14159d;    }    @Override    public String toString() {        return "Example [mFiledOne=" + mFiledOne + ", mCount=" + mCount + "]";    }    private String tellSecret(String name, int num) {        String result = name + num + toString();        return result;    }}
复制代码
复制代码
package com.mengdd.reflect;import org.junit.Assert;import org.junit.Test;public class ReflectTest {    @Test    public void testNewInstance() {        Object object = ReflectUtils.newInstance("com.mengdd.reflect.Example");        Assert.assertNotNull(object);    }    @Test    public void testGetConstructorInfo() {        String result = ReflectUtils                .getPublicConstructorInfo("com.mengdd.reflect.Example");        System.out                .println("=============testGetConstructorInfo================");        System.out.println(result);        System.out                .println("===================================================");        Assert.assertNotNull(result);    }    @Test    public void testFieldInfos() {        String result = ReflectUtils                .getDecleardFieldInfo("com.mengdd.reflect.Example");        System.out.println("=============testFieldInfos================");        System.out.println(result);        System.out                .println("===================================================");        Assert.assertNotNull(result);    }    @Test    public void testMethodInfos() {        String result = ReflectUtils                .getDeclaredMethodInfos("com.mengdd.reflect.Example");        System.out.println("=============testMethodInfos================");        System.out.println(result);        System.out                .println("===================================================");        Assert.assertNotNull(result);    }    @Test    public void testPublicStaticInvocation() {        System.out                .println("=============test static invocation================");        try {            // 静态方法1            ReflectUtils.invokePublicStaticMethod("com.mengdd.reflect.Example",                    "printSomething", new Class<?>[] { String.class },                    new Object[] { "Hello World" });            // 静态方法2            Object result1 = ReflectUtils.invokePublicStaticMethod(                    "com.mengdd.reflect.Example", "add", new Class<?>[] {                            int.class, Integer.TYPE }, new Object[] { 1, 2 });            // int.class和Integer.TYPE都行            Assert.assertEquals(3, result1);            // 静态方法3            Object result2 = ReflectUtils.invokePublicStaticMethod(                    "com.mengdd.reflect.Example", "getPi", new Class<?>[] {},                    new Object[] {});            Assert.assertEquals(3.14159, result2);        }        catch (Exception e) {            e.printStackTrace();            System.out.println("Exception!");        }        System.out                .println("===================================================");    }    @Test    public void testPrivateInvocation() {        Example example = new Example("1", 5, 0);        Object secret = null;        try {            secret = ReflectUtils.invokePrivateMethod(example, "tellSecret",                    new Class<?>[] { String.class, Integer.TYPE },                    new Object[] { "Hello", 2 });        }        catch (Exception e) {            e.printStackTrace();        }        String expected = "Hello2Example [mFiledOne=1, mCount=5]";        Assert.assertEquals(expected, secret);    }}

0 0
原创粉丝点击