• Java 反射的应用


      在学习反射之前,让我们先了解“类(Class)”。“方法”、“属性”、“类”都是名词,那么相应的在Java中会有这样一些特殊的类:“方法类(Method类)”、“属性类(Field类)”、“构造器类(Constructor类)”、“类类(Class类)”。

      如上所示,任何Java的类或接口都是Class类的一个实例。

      反射就是Java自我管理这些(类,对象)的机制。

      1) 反射的作用

      • 可以通过反射机制发现对象的类型,发现类型的方法/属性/构造器
      • 可以创建对象并访问任意对象方法和属性等

      2) Class加载

        类加载到内存:Java将磁盘类文件加载到内存中吗,为一个对象(实例),这个对象是Class的实例。

      3) Class实例代表Java中类型

      • 获得基本类型实例
        • int.class
        • long.class
        • ...
      • 获得类类型(Class)实例:
    Class cls = String.class;
    Class cls = Class.forName("java.lang.String");
    Class cls = "abc".getClass();

    1.通过放射获得队形的类/属性/方法/构造器

     【案例】反射演示_“发现”对象的类/属性/方法/构造器

    • 版本01
    package reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    
    /**
     * 反射演示
     */
    public class Demo1 {
        public static void main(String[] args) throws ClassNotFoundException {
            reflect("s");    //java.lang.String
            reflect(1);        //java.lang.Integer
        }
        
        /**
         * 反射方法,用于发现
         *         obj 的类型是什么
         *         obj 有哪些属性
         *         obj 有哪些方法
         *         obj 有哪些构造器
         * @param obj 表示被“反射”的对象,被用于“发现”的对象
         */
        public static void reflect(Object obj) {
            //1. getClass()
            //      返回对象的类型,是Object类的方法
            Class<?> cls = obj.getClass();
            System.out.println("类:" + cls.getName());
            //2. getDeclaredFields();
            //   返回在类上获得声明的所有属性(字段)
            Field[] fields = cls.getDeclaredFields();
            System.out.println("属性:");
            for(Field field : fields) {
                System.out.println(
                        field.getType()+" :" + //属性类型
                        field.getName());        //属性名称
            }
            //3. getDeclaredMethods
            //   返回在类上获得声明的所有方法
            Method[] methods = cls.getDeclaredMethods();
            System.out.println("方法:");
            for(Method method : methods) {
                System.out.print(method.getReturnType()+" ");
                System.out.print(method.getName()+" ");
                System.out.println(
                        Arrays.toString(method.getParameterTypes()));
            }
            //4. getDeclaredConstructors
            //   返回在类上获得声明的所有构造器
            Constructor[] constructors = cls.getDeclaredConstructors();
            System.out.println("构造器:");
            for(Constructor c : constructors) {
                System.out.print(c.getName() + " ");
                System.out.println(
                        Arrays.toString(c.getParameterTypes()));
            }
        }
    
    }
    • 版本02
    package reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    
    /**
     *反射演示
     */
    public class Demo2 {
        public static void main(String[] args) throws ClassNotFoundException {
            reflect(new Foo());    //reflect.Foo
        }
        
        /**
         * 反射方法,用于发现
         *         obj 的类型是什么
         *         obj 有哪些属性
         *         obj 有哪些方法
         *         obj 有哪些构造器
         * @param obj 表示被“反射”的对象,被用于“发现”的对象
         */
        public static void reflect(Object obj) {
            //1. getClass()
            //      返回对象的类型,是Object类的方法
            Class<?> cls = obj.getClass();
            System.out.println("类:" + cls.getName());
            //2. getDeclaredFields();
            //   返回在类上获得声明的所有属性(字段)
            Field[] fields = cls.getDeclaredFields();
            System.out.println("属性:");
            for(Field field : fields) {
                System.out.println(
                        field.getType()+" :" + //属性类型
                        field.getName());        //属性名称
            }
            //3. getDeclaredMethods
            //   返回在类上获得声明的所有方法
            Method[] methods = cls.getDeclaredMethods();
            System.out.println("方法:");
            for(Method method : methods) {
                System.out.print(method.getReturnType()+" ");
                System.out.print(method.getName()+" ");
                System.out.println(
                        Arrays.toString(method.getParameterTypes()));
            }
            //4. getDeclaredConstructors
            //   返回在类上获得声明的所有构造器
            Constructor[] constructors = cls.getDeclaredConstructors();
            System.out.println("构造器:");
            for(Constructor c : constructors) {
                System.out.print(c.getName() + " ");
                System.out.println(
                        Arrays.toString(c.getParameterTypes()));
            }
        }
    
    }
    class Foo {
        int a = 3;
        public double add(int b, Double d) {
            return a+b+d;
        }
        
    }

    结果:

      Java是如何知道程序员开发程序的类、属性、方法的?通过反射技术(反射技术是Java底层JVM运行程序的机制)

      如下所示,Eclipse开发工具的“代码提示”功能就是利用反射写的。

    2.通过发射创建对象实例

    【案例】反射演示_根据类名创建对象实例

    package reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    /**
     *反射演示
     */
    public class Demo3 {
        public static void main(String[] args) throws Exception {
            //执行create()方法前提是参数类有无参构造器
            Object obj = create("reflect.Foo3");
            reflect(obj);
            reflect(create("java.lang.String"));
        }
        /**
         * 任务1:根据“类名”创建对象实例
         * @param className
         * @return
         */
        public static Object create(String className) {
            try {
                //1        加载类
                //1.1    在classpath中查找对应的类
                //1.2    采用“懒加载”方式装载到内存
                Class cls = Class.forName(className);
                //2        创建类实例
                Object obj = cls.newInstance();
                return obj;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("没搞定!", e);
            }
        }
        
        /**
         * 反射方法,用于发现
         *         obj 的类型是什么
         *         obj 有哪些属性
         *         obj 有哪些方法
         *         obj 有哪些构造器
         * @param obj 表示被“反射”的对象,被用于“发现”的对象
         * @throws Exception 
         */
        public static void reflect(Object obj) throws Exception {
            //1.    getClass()
            //        返回对象的类型,是Object类的方法
            Class<?> cls = obj.getClass();
            System.out.println("类:" + cls.getName());
            //2.    getDeclaredFields();
            //        返回在类上获得声明的所有属性(字段)
            Field[] fields = cls.getDeclaredFields();
            System.out.println("属性:");
            for(Field field : fields) {
                System.out.println(
                        field.getType()+" :" + //属性类型
                        field.getName());        //属性名称
            }
            //3.    getDeclaredMethods
            //        返回在类上获得声明的所有方法
            Method[] methods = cls.getDeclaredMethods();
            for(Method method : methods) {
                System.out.print(method.getReturnType()+" ");
                System.out.print(method.getName()+" ");
                System.out.println(
                        Arrays.toString(method.getParameterTypes()));
            }
            //4.    getDeclaredConstructors
            //        返回在类上获得声明的所有构造器
            Constructor[] constructors = cls.getDeclaredConstructors();
            System.out.println("构造器:");
            for(Constructor c : constructors) {
                System.out.print(c.getName() + " ");
                System.out.println(
                        Arrays.toString(c.getParameterTypes()));
            }
        }
    }
    
    class Foo3 {
        int a = 3;
        public double add(int b, Double d) {
            return a+b+d;
        }
    }

    注:

    • Class.forName() 静态方法,可以利用类名在CLASSPATH中查找对应的类,并且装载到内存,返回这个“class”
    • Class.forName() 加载类的过程采用“懒惰方式
      • 懒惰方式”,即检查发现如果已经加载了(内存中存在)就不再加载,直接返回已经加载的类,相当于“手工”去检查内存在是否已经加载某个类
    • newInstance() 方法,会利用默认(无参数)构造器创建类实例(实例对象)

    3.通过反射访问某对象的某属性

    【案例】反射演示_访问某对象的某属性

    package reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    /**
     *反射演示
     */
    public class Demo4 {
        public static void main(String[] args) throws Exception {
            //执行create()方法前提是参数类有无参构造器
            Object obj = create("reflect.Foo4");
            System.out.println(getFieldValue(obj, "a"));
        }
        /**
         * 任务1:根据“类名”创建对象实例
         * @param className
         * @return
         */
        public static Object create(String className) {
            try {
                //1        加载类
                //1.1    在classpath中查找对应的类
                //1.2    采用“懒加载”方式装载到内存
                Class cls = Class.forName(className);
                //2        创建类实例
                Object obj = cls.newInstance();
                return obj;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("没搞定!", e);
            }
        }
        /**
         * 任务2:访问某对象的某属性
         * @param obj
         * @param fieldName
         * @return
         */
        public static Object getFieldValue(
                Object obj, String fieldName) {
            try {
                //1.    反射出类型
                Class cls = obj.getClass();
                //2.    反射出类型字段
                Field field = cls.getDeclaredField(fieldName);
                //3.    在对象obj上读取field属性值
                Object val = field.get(obj);
                return val;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("没搞定!", e);
            }
        }
        /**
         * 反射方法,用于发现
         *         obj 的类型是什么
         *         obj 有哪些属性
         *         obj 有哪些方法
         *         obj 有哪些构造器
         * @param obj 表示被“反射”的对象,被用于“发现”的对象
         * @throws Exception 
         */
        public static void reflect(Object obj) throws Exception {
            //1.    getClass()
            //        返回对象的类型,是Object类的方法
            Class<?> cls = obj.getClass();
            System.out.println("类:" + cls.getName());
            //2.    getDeclaredFields();
            //        返回在类上获得声明的所有属性(字段)
            Field[] fields = cls.getDeclaredFields();
            System.out.println("属性:");
            for(Field field : fields) {
                System.out.println(
                        field.getType()+" :" + //属性类型
                        field.getName());        //属性名称
            }
            //3.    getDeclaredMethods
            //        返回在类上获得声明的所有方法
            Method[] methods = cls.getDeclaredMethods();
            for(Method method : methods) {
                System.out.print(method.getReturnType()+" ");
                System.out.print(method.getName()+" ");
                System.out.println(
                        Arrays.toString(method.getParameterTypes()));
            }
            //4.    getDeclaredConstructors
            //        返回在类上获得声明的所有构造器
            Constructor[] constructors = cls.getDeclaredConstructors();
            System.out.println("构造器:");
            for(Constructor c : constructors) {
                System.out.print(c.getName() + " ");
                System.out.println(
                        Arrays.toString(c.getParameterTypes()));
            }
        }
    }
    
    class Foo4 {
        int a = 3;
        public double add(int b, Double d) {
            return a+b+d;
        }
    }

    注:

      field.get(obj) 可以获得对象属性值

      field.set(Object obj, Object value) 可以设置对象属性值

    4.通过反射方位某对象的方法

    【案例】反射演示_访问某对象的某方法

    package reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    /**
     *反射演示
     */
    public class Demo5 {
        public static void main(String[] args) throws Exception {
            //执行create()方法前提是参数类有无参构造器
            Object obj = create("reflect.Foo5");
            Object mObj = call(
                    obj,                                     //obj
                    "add",                                     //方法名
                    new Class[]{int.class, Double.class},     //参数类型
                    new Object[]{2, 3.5});                    //参数
            System.out.println(mObj);
        }
        /**
         * 任务1:根据“类名”创建对象实例
         * @param className
         * @return
         */
        public static Object create(String className) {
            try {
                //1        加载类
                //1.1    在classpath中查找对应的类
                //1.2    采用“懒加载”方式装载到内存
                Class cls = Class.forName(className);
                //2        创建类实例
                Object obj = cls.newInstance();
                return obj;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("没搞定!", e);
            }
        }
        /**
         * 任务2:访问某对象的某属性
         * @param obj
         * @param fieldName
         * @return
         */
        public static Object getFieldValue(
                Object obj, String fieldName) {
            try {
                //1.    反射出类型
                Class cls = obj.getClass();
                //2.    反射出类型字段
                Field field = cls.getDeclaredField(fieldName);
                //3.    在对象obj上读取field属性值
                Object val = field.get(obj);
                return val;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("没搞定!", e);
            }
        }
        
        /**
         * 任务3:访问某对象的某方法
         * @param obj            被调用对象
         * @param method        方法名
         * @param paramTypes    方法参数类型列表
         * @param params        方法调用参数列表
         * @return     在对象obj上调用方法签名是(method,paramTypes)的方法,
         *             params是传递的参数,返回的是方法的结果,
         *             如果无返回值,返回null
         */
        public static Object call(
                Object obj,
                String method,
                Class[] paramTypes,
                Object[] params) {
            try {
                //1.    发现类型
                Class cls = obj.getClass();
                //2.    发现方法
                Method m = cls.getDeclaredMethod(method, paramTypes);
                //3.    在对象obj调用方法m,传递参数类别params
                Object val = m.invoke(obj, params);
                return val;
            } catch(Exception e) {
                throw new RuntimeException("错误了!", e);
            }
        }
        
        
        /**
         * 反射方法,用于发现
         *         obj 的类型是什么
         *         obj 有哪些属性
         *         obj 有哪些方法
         *         obj 有哪些构造器
         * @param obj 表示被“反射”的对象,被用于“发现”的对象
         * @throws Exception 
         */
        public static void reflect(Object obj) throws Exception {
            //1.    getClass()
            //        返回对象的类型,是Object类的方法
            Class<?> cls = obj.getClass();
            System.out.println("类:" + cls.getName());
            //2.    getDeclaredFields();
            //        返回在类上获得声明的所有属性(字段)
            Field[] fields = cls.getDeclaredFields();
            System.out.println("属性:");
            for(Field field : fields) {
                System.out.println(
                        field.getType()+" :" + //属性类型
                        field.getName());        //属性名称
            }
            //3.    getDeclaredMethods
            //        返回在类上获得声明的所有方法
            Method[] methods = cls.getDeclaredMethods();
            for(Method method : methods) {
                System.out.print(method.getReturnType()+" ");
                System.out.print(method.getName()+" ");
                System.out.println(
                        Arrays.toString(method.getParameterTypes()));
            }
            //4.    getDeclaredConstructors
            //        返回在类上获得声明的所有构造器
            Constructor[] constructors = cls.getDeclaredConstructors();
            System.out.println("构造器:");
            for(Constructor c : constructors) {
                System.out.print(c.getName() + " ");
                System.out.println(
                        Arrays.toString(c.getParameterTypes()));
            }
        }
    }
    
    class Foo5 {
        int a = 3;
        public double add(int b, Double d) {
            return a+b+d;
        }
    }

    注:

    • 方法签名由方法名称与参数列表组成(没有返回值和访问控制符),被成为方法签名
    • call 方法标识,调用任意对象的任意方法
      • 调用无参方法时这样写:

    PS:

    getDeclaredMethod*()获取的是类自身声明的所有方法,包含public、protected和private方法。

    getMethod*()获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。

    java.lang.reflect.Method.invoke(Object obj, Object... args) invoke第一个参数obj,如果电泳的方法是static方法,obj参数可以传null。

  • 相关阅读:
    Linux03__管理
    Linux02__常用命令
    Linux01__系统安装
    爬虫性能相关
    【转载】资源整合
    Continuous integration
    行业巨头的云计算冷数据存储应用和比较 2016-07-15
    win7中使用docker ——配置阿里云容器加速
    layui treeSelect插件的使用
    springboot 拦截器设置
  • 原文地址:https://www.cnblogs.com/chaizp/p/5128297.html
Copyright © 2020-2023  润新知