美文网首页
Java 反射总结

Java 反射总结

作者: Xander_Wang | 来源:发表于2016-12-08 11:43 被阅读16次

    什么是反射官方有段介绍是这么说的

    Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine.

    什么意思呢,就是说反射通常用于需要能够检查或修改Java虚拟机中运行的应用程序的运行时行为的程序。不是很好懂,我们说下反射能做什么吧。

    1. 反射可以在运行时动态生成某个类的实例。
    2. 反射可以在运行时获取某个类的任何的变量并修改变量的值。
    3. 反射可以在运行时执行某个类的任何方法。

    如何使用反射

    我们针对上面的情况一一说一下如何使用。
    我们先定义一个 com.reflect.Demo.java 用来做我们后续的实验。

    package com.reflect;
    public class Demo { 
        public String pubStr = "public_string"; 
        private String priStr = "private_string"; 
        private String getPriStr(String testParam) { 
            pubStr = testParam; 
            return priStr; 
        } 
    
        private String getPriStr() { 
            return priStr; 
        } 
    
        public Demo() { 
    
        } 
    
        private Demo( String priStr ) { 
            this.priStr = priStr; 
        } 
    
        @Override 
        public String toString() { 
            return "Demo{" + 
                       "pubStr='" + pubStr + '\'' + 
                       ", priStr='" + priStr + '\'' + 
                       '}'; 
        }
    }
    

    在运行时动态生成某个类的实例

    // 反射第一步是获取类的 class , 一般有 3 种写法
    Class demoClass = Class.forName("com.reflect.Demo");
    // demoClass = Demo.class;
    // demoClass = new Demo().getClass();
    // 获取无参构造函数
    Constructor constructor = demoClass.getDeclaredConstructor();
    // 设置可以访问
    constructor.setAccessible(true);
    // 根据构造方法创建实例
    Object demo = constructor.newInstance();
    // 获取有参构造函数
    Constructor constructor1 = demoClass.getDeclaredConstructor(String.class);
    // 设置可以访问
    constructor1.setAccessible(true);
    // 根据构造方法创建实例
    Object demo1 = constructor1.newInstance("I am String");
    

    下面介绍一种通用的获取某个类的实例的方法

    /** 
     * 运用反射,通过默认的构造方法获取某个类的实例 
     * @param className
     * @return
     */ 
    public static Object getObjectInstance(String className, Object... args) { 
        try { 
            Class[] classes = new Class[args.length]; 
            for (int i = 0; i < args.length; i++) { 
                classes[i] = args[i].getClass(); 
            } 
            Class objClass = Class.forName(className); 
            Constructor constructor = objClass.getDeclaredConstructor(classes);
            constructor.setAccessible(true); 
            return constructor.newInstance(args); 
        } catch (ClassNotFoundException e) { 
            e.printStackTrace(); 
        } catch (NoSuchMethodException e) { 
            e.printStackTrace(); 
        } catch (InstantiationException e) { 
            e.printStackTrace(); 
        } catch (IllegalAccessException e) { 
            e.printStackTrace(); 
        } catch (InvocationTargetException e) { 
            e.printStackTrace(); 
        } 
        return new Object(); 
    }
    

    在运行时获取某个类的任何的变量并修改变量的值

    下面的代码会告诉大家如何获取 Demo.java 的一个实例的变量 (priStr) 并对其赋值。

    // 无参构造方法 new 的实例,里面的 priStr 值为 private_string
    Demo demo = new Demo();
    // 获取 demo 的 class
    Class demoClass = demo.getClass();
    // 获取 priStr 的 Field 
    Field priStrField = demoClass.getDeclaredField("priStr");
    // 设置可以访问
    priStrField.setAccessible(true);
    // 取 priStr 的值
    // 要取的是 demo 这个实例的 priStr , 所以需要传入 demo
    Object priStrValue = priStrField.get(demo); 
    // 修改 priStr 的值
    // 要修改的是 demo 这个实例, 所以需要传入 demo
    priStrField.set(demo,"I am Private String"); 
    

    下面介绍一种通用的获取属性的方法

    /** 
     * 获取某个变量的值 * 
     * @param obj 待取值的类 
     * @param fieldName 待取值的变量的变量名 
     * @return 
     */ 
    public static Object getFieldValue(Object obj, String fieldName) { 
        try { 
            Field field = obj.getClass().getDeclaredField(fieldName); 
            field.setAccessible(true); 
            return field.get(obj); 
        } catch (NoSuchFieldException e) { 
            e.printStackTrace(); 
        } catch (IllegalAccessException e) { 
            e.printStackTrace(); 
        } 
        return new Object(); 
    } 
    
    /** 
     * 设置某个类的某个变量的值 * 
     * @param obj 
     * @param fieldName 
     * @param fieldValue 
     * @return 
     */ 
    public static boolean setFieldValue(Object obj, String fieldName, Object fieldValue) { 
        try { 
            Field field = obj.getClass().getDeclaredField(fieldName); 
            field.setAccessible(true);
            field.set(obj, fieldValue); 
            return true; 
        } catch (NoSuchFieldException e) { 
            e.printStackTrace(); 
        } catch (IllegalAccessException e) { 
            e.printStackTrace(); 
        } 
        return false;
    }
    

    在运行时执行某个类的任何方法

    下面的代码会告诉大家如何获取 Demo.java 的一个方法(getPriStr) 并调用此方法。

    // 无参构造方法 new 的实例,里面的 priStr 值为 private_string
    Demo demo = new Demo();
    // 获取 demo 的 class
    Class demoClass = demo.getClass();
    // 获取无参 getPriStr 对应的 Method 
    Method priStrMethod = demoClass.getDeclaredMethod("priStr");
    // 设置可以访问
    priStrMethod.setAccessible(true);
    // 调用此方法
    Object priStr = priStrMethod.invoke(obj);
    // 获取有参 getPriStr 对应的 Method 
    Method priStrMethod1 = demoClass.getDeclaredMethod("priStr",String.class);
    // 设置可以访问
    priStrMethod1.setAccessible(true);
    // 调用此方法
    Object priStr1 = priStrMethod1.invoke(obj,"I am testParam");
    

    下面介绍一种通用的调用对象的方法

    /**
     * 调用某个方法
     * @param obj
     * @param methodName
     * @param args 
     * @return
     */ 
    public static Object invokMethod(Object obj, String methodName, Object... args) { 
        try { 
            Class[] classes = new Class[args.length]; 
            for (int i = 0; i < args.length; i++) { 
                classes[i] = args[i].getClass(); 
            } 
            Method method = obj.getClass().getDeclaredMethod(methodName, classes); 
            method.setAccessible(true); 
            method.invoke(obj,args); 
            return method.invoke(obj, args); 
        } catch (IllegalAccessException e) { 
            e.printStackTrace(); 
        } catch (NoSuchMethodException e) { 
            e.printStackTrace(); 
        } catch (InvocationTargetException e) { 
            e.printStackTrace(); 
        } 
        return new Object(); 
        }
    

    更多用法可参考 DEMO

    相关文章

      网友评论

          本文标题:Java 反射总结

          本文链接:https://www.haomeiwen.com/subject/ofxsmttx.html