精华内容
下载资源
问答
  • Java反射技术详解

    万次阅读 多人点赞 2019-04-14 23:11:32
    相信很多人都知道反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的,比如最初的很多注解框架,后来因为java反射影响性能,所以被运行时注解APT替代了,java反射有...

    前言

      相信很多人都知道反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的,比如最初的很多注解框架,后来因为java反射影响性能,所以被运行时注解APT替代了,java反射有个开源框架jOOR相信很多人都用过,不过我们还是要学习反射的基础语法,这样才能自己写出优秀的框架,当然这里所讲的反射技术,是学习Android插件化技术、Hook技术等必不可少的!

    一、基本反射技术

          1.1 根据一个字符串得到一个类

            getClass方法

     String name = "Huanglinqing";
     Class c1 = name.getClass();
     System.out.println(c1.getName());
    

         打印结果如下:

        

        Class.forName

        比如我们获取java.lang.String的类名 

       String name = "java.lang.String";
       Class c1 = null;
       try {
              c1 = Class.forName(name);
              System.out.println(c1.getName());
          } catch (ClassNotFoundException e) {
      }
    

        这里也通过捕获异常,因为我们传的这个字符串可能不合法,字符串合法命名是类的命名空间和类的名称组成

        打印结果如下:

        
       我们还可以通过c1.getSuperclass()获取到他的父类

       Type属性

        基本类型都有type属性,可以得到这个基本类型的类型,比如:

    Class c1 = Boolean.TYPE;
    Class c2 = Byte.TYPE;
    Class c3 = Float.TYPE;
    Class c4 = Double.TYPE;
    
     停停停!这些东西有啥子用,如此鸡肋! 别急,一切都是为后续做准备。

    二、获取类的成员

             当类中方法定义为私有的时候我们能调用?不能!当变量是私有的时候我们能获取吗?不能!但是反射可以,比如源码中有你需要用到的方法,但是那个方法是私有的,这个时候你就可以通过反射去执行这个私有方法,并且获取私有变量。

           获取类的构造函数

           为了便于测试,我们定义一个Test类,Test类如下:(省略get和set方法)

           Test类中我们定义是三个私有变量,生成两个公有的含参构造方法和一个私有的含参构造方法以及一个公有的无参构造方法。

    public class Test {
    
        private int age;
        private String name;
        private int testint;
    
        public Test(int age) {
            this.age = age;
        }
    
        public Test(int age, String name) {
            this.age = age;
            this.name = name;
        }
    
        private Test(String name) {
            this.name = name;
        }
    
        public Test() {
        }
    

          下面我们通过反射获取这些构造方法

           获取类的所有构造方法

     Test test = new Test();
     Class c4 = test.getClass();
     Constructor[] constructors ;
     constructors = c4.getDeclaredConstructors();
    

          通过getDeclaredConstructors可以返回类的所有构造方法,返回的是一个数组因为构造方法可能不止一个,通过getModifiers可以得到构造方法的类型,getParameterTypes可以得到构造方法的所有参数,返回的是一个Class数组,所以我们如果想获取所有构造方法以及每个构造方法的参数类型,可以有如下代码:

      for (int i = 0; i < constructors.length; i++) {
            System.out.print(Modifier.toString(constructors[i].getModifiers()) + "参数:");
            Class[] parametertypes = constructors[i].getParameterTypes();
            for (int j = 0; j < parametertypes.length; j++) {
                 System.out.print(parametertypes[j].getName() + " ");
           }
          System.out.println("");
      }
    

        运行结果如下所示:

        

        这样我们就得到了类中所有构造方法和构造方法中的参数,那么我们如何获取特定的构造方法呢?

        获取类中特定的构造方法

        我们可以通过getConstructors方法获取类中 所有的public类型的构造方法,代码和上面一样就不演示了。

        我们可以通过getDeclaredConstructor()方法传参获取特定参数类型的构造方法,这里注意是getDeclaredConstructor()不是  getDeclaredConstructors() ,所以返回的是一个Class对象而不是一个Class数组。

        获取无参构造方法直接不传参数,如下所示:

       try {
              constructors = c4.getDeclaredConstructor();
              System.out.print(Modifier.toString(constructors.getModifiers()) + );
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
          }
    

        这里要进行异常捕获,因为可能不存在对应的构造方法,打印结果如下:  

        

       如果我们想获取有两个参数分别为int和String类型的构造方法,代码如下:

      Class[] p = {int.class,String.class};
      try {
           constructors = c4.getDeclaredConstructor(p);
           System.out.print(Modifier.toString(constructors.getModifiers()) + "参数:");
           Class[] parametertypes = constructors.getParameterTypes();
           for (int j = 0; j < parametertypes.length; j++) {
                System.out.print(parametertypes[j].getName() + " ");
              }
           } catch (NoSuchMethodException e) {
                e.printStackTrace();
         }
    

      这里我们同样打印出构造方法的参数:


      

      调用构造方法

       从这里开始慢慢到了关键的一步,得到类的实例,我们主要借助于newInstance方法,为了方便演示我们将测试类的两个构造方法打印出来. 

       public Test(int age, String name) {
            this.age = age;
            this.name = name;
            System.out.println("hello" + name + "i am" + age);
        }
    
    
        private Test(String name) {
            this.name = name;
            System.out.println("My Name is" +
                    name);
        }
    

       我们先来调用public的方法,如下所示:

     Class[] p = {int.class,String.class};
     constructors = c4.getDeclaredConstructor(p);
     constructors.newInstance(24,"HuangLinqing");
    

     运行打印结果如下:


      

     那么调用私有构造方法呢,和上面一样,只是我们要设置constructors.setAccessible(true);代码如下:

      Class[] p = {String.class};
      constructors = c4.getDeclaredConstructor(p);
      constructors.setAccessible(true);
      constructors.newInstance("HuangLinqing");
    

      打印结果如下:


       

    调用类的私有方法

      如何调用类中的私有方法呢,我们先在测试类中编写一个测试的私有方法 如下:

      private void welcome(String tips){
            System.out.println(tips);
        }
    

      我们知道如果我们要正常的调用类的方法都是通过类.方法调用,所以我们调用私有方法也需要得到类的实例,而我们上面newInstace已经得到了类的实例,这样就好办了。

       Class[] p4 = {String.class};
       Method method = c4.getDeclaredMethod("welcome",p4);
       method.setAccessible(true);
    

       我们首先通过 getDeclaredMethod方法获取到这个私有方法,第一个参数是方法名,第二个参数是参数类型

       然后通过invoke方法执行,invoke需要两个参数一个是类的实例,一个是方法参数。

         Class[] p4 = {String.class};
         Method method = c4.getDeclaredMethod("welcome",p4);
         method.setAccessible(true);
         Object arg1s[] = {"欢迎关注代码男人技术公众号"};
         method.invoke(test,arg1s);
    

         test类的实例当不能new 获取的时候我们也可以通过反射获取,就是上面的newInstance方法。打印结果如下:


        

     获取类的私有字段并修改值

      看到这里你可能会说,有了set方法,什么私有不私有,test.set不就可以了,但是这里要注意我们是没有办法得到这个类的实例的,要不然都可以得到实例就没有反射一说了。我们在通过反射得到类的实例之后先获取字段:

    Field field = c4.getDeclaredField("name");
    field.setAccessible(true);
    field.set(o,"代码男人");
    

       o是我们上面通过反射构造方法获取的实例,  打印field.get(o).toString()的值如下:
      

       

       不过要注意的是我们修改了name的值只对当前的实例对象有效。

     

       Java的基本反射语法就是这样了,欢迎加入技术群一起探讨!

      最后反射封装类如下:

    package jnidemo.hlq.com.hookdemo;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    /**
     * @author Huanglinqing
     * @date 2019/4/28
     */
    
    public class Reflex {
    
        /**
         * 获取无参构造函数
         * @param className
         * @return
         */
        public static Object createObject(String className) {
            Class[] pareTyples = new Class[]{};
            Object[] pareVaules = new Object[]{};
    
            try {
                Class r = Class.forName(className);
                return createObject(r, pareTyples, pareVaules);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
        /**
         * 获取无参构造方法
         * @param clazz
         * @return
         */
        public static Object createObject(Class clazz) {
            Class[] pareTyple = new Class[]{};
            Object[] pareVaules = new Object[]{};
    
            return createObject(clazz, pareTyple, pareVaules);
        }
    
        /**
         * 获取一个参数的构造函数  已知className
         *
         * @param className
         * @param pareTyple
         * @param pareVaule
         * @return
         */
        public static Object createObject(String className, Class pareTyple, Object pareVaule) {
    
            Class[] pareTyples = new Class[]{pareTyple};
            Object[] pareVaules = new Object[]{pareVaule};
    
            try {
                Class r = Class.forName(className);
                return createObject(r, pareTyples, pareVaules);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
    
        /**
         * 获取单个参数的构造方法 已知类
         *
         * @param clazz
         * @param pareTyple
         * @param pareVaule
         * @return
         */
        public static Object createObject(Class clazz, Class pareTyple, Object pareVaule) {
            Class[] pareTyples = new Class[]{pareTyple};
            Object[] pareVaules = new Object[]{pareVaule};
    
            return createObject(clazz, pareTyples, pareVaules);
        }
    
        /**
         * 获取多个参数的构造方法 已知className
         * @param className
         * @param pareTyples
         * @param pareVaules
         * @return
         */
        public static Object createObject(String className, Class[] pareTyples, Object[] pareVaules) {
            try {
                Class r = Class.forName(className);
                return createObject(r, pareTyples, pareVaules);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
    
        /**
         * 获取构造方法
         *
         * @param clazz
         * @param pareTyples
         * @param pareVaules
         * @return
         */
        public static Object createObject(Class clazz, Class[] pareTyples, Object[] pareVaules) {
            try {
                Constructor ctor = clazz.getDeclaredConstructor(pareTyples);
                ctor.setAccessible(true);
                return ctor.newInstance(pareVaules);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
    
        /**
         * 获取多个参数的方法
         * @param obj
         * @param methodName
         * @param pareTyples
         * @param pareVaules
         * @return
         */
        public static Object invokeInstanceMethod(Object obj, String methodName, Class[] pareTyples, Object[] pareVaules) {
            if (obj == null) {
                return null;
            }
    
            try {
                //调用一个private方法 //在指定类中获取指定的方法
                Method method = obj.getClass().getDeclaredMethod(methodName, pareTyples);
                method.setAccessible(true);
                return method.invoke(obj, pareVaules);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
        /**
         * 获取一个参数的方法
         * @param obj
         * @param methodName
         * @param pareTyple
         * @param pareVaule
         * @return
         */
        public static Object invokeInstanceMethod(Object obj, String methodName, Class pareTyple, Object pareVaule) {
            Class[] pareTyples = {pareTyple};
            Object[] pareVaules = {pareVaule};
    
            return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules);
        }
    
        /**
         * 获取无参方法
         * @param obj
         * @param methodName
         * @return
         */
        public static Object invokeInstanceMethod(Object obj, String methodName) {
            Class[] pareTyples = new Class[]{};
            Object[] pareVaules = new Object[]{};
    
            return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules);
        }
    
    
        /**
         * 无参静态方法
         * @param className
         * @param method_name
         * @return
         */
        public static Object invokeStaticMethod(String className, String method_name) {
            Class[] pareTyples = new Class[]{};
            Object[] pareVaules = new Object[]{};
    
            return invokeStaticMethod(className, method_name, pareTyples, pareVaules);
        }
    
        /**
         * 获取一个参数的静态方法
         * @param className
         * @param method_name
         * @param pareTyple
         * @param pareVaule
         * @return
         */
        public static Object invokeStaticMethod(String className, String method_name, Class pareTyple, Object pareVaule) {
            Class[] pareTyples = new Class[]{pareTyple};
            Object[] pareVaules = new Object[]{pareVaule};
    
            return invokeStaticMethod(className, method_name, pareTyples, pareVaules);
        }
    
        /**
         * 获取多个参数的静态方法
         * @param className
         * @param method_name
         * @param pareTyples
         * @param pareVaules
         * @return
         */
        public static Object invokeStaticMethod(String className, String method_name, Class[] pareTyples, Object[] pareVaules) {
            try {
                Class obj_class = Class.forName(className);
                return invokeStaticMethod(obj_class, method_name, pareTyples, pareVaules);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
        /**
         * 无参静态方法
         * @param method_name
         * @return
         */
        public static Object invokeStaticMethod(Class clazz, String method_name) {
            Class[] pareTyples = new Class[]{};
            Object[] pareVaules = new Object[]{};
    
            return invokeStaticMethod(clazz, method_name, pareTyples, pareVaules);
        }
    
        /**
         * 一个参数静态方法
         * @param clazz
         * @param method_name
         * @param classType
         * @param pareVaule
         * @return
         */
        public static Object invokeStaticMethod(Class clazz, String method_name, Class classType, Object pareVaule) {
            Class[] classTypes = new Class[]{classType};
            Object[] pareVaules = new Object[]{pareVaule};
    
            return invokeStaticMethod(clazz, method_name, classTypes, pareVaules);
        }
    
        /**
         * 多个参数的静态方法
         * @param clazz
         * @param method_name
         * @param pareTyples
         * @param pareVaules
         * @return
         */
        public static Object invokeStaticMethod(Class clazz, String method_name, Class[] pareTyples, Object[] pareVaules) {
            try {
                Method method = clazz.getDeclaredMethod(method_name, pareTyples);
                method.setAccessible(true);
                return method.invoke(null, pareVaules);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
    
        public static Object getFieldObject(String className, Object obj, String filedName) {
            try {
                Class obj_class = Class.forName(className);
                return getFieldObject(obj_class, obj, filedName);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static Object getFieldObject(Class clazz, Object obj, String filedName) {
            try {
                Field field = clazz.getDeclaredField(filedName);
                field.setAccessible(true);
                return field.get(obj);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
    
        public static void setFieldObject(Class clazz, Object obj, String filedName, Object filedVaule) {
            try {
                Field field = clazz.getDeclaredField(filedName);
                field.setAccessible(true);
                field.set(obj, filedVaule);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void setFieldObject(String className, Object obj, String filedName, Object filedVaule) {
            try {
                Class obj_class = Class.forName(className);
                setFieldObject(obj_class, obj, filedName, filedVaule);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
    
        public static Object getStaticFieldObject(String className, String filedName) {
            return getFieldObject(className, null, filedName);
        }
    
        public static Object getStaticFieldObject(Class clazz, String filedName) {
            return getFieldObject(clazz, null, filedName);
        }
    
        public static void setStaticFieldObject(String classname, String filedName, Object filedVaule) {
            setFieldObject(classname, null, filedName, filedVaule);
        }
    
        public static void setStaticFieldObject(Class clazz, String filedName, Object filedVaule) {
            setFieldObject(clazz, null, filedName, filedVaule);
        }
    }
    
    
     
    展开全文
  • Java反射

    万次阅读 多人点赞 2019-08-28 22:58:42
    Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。 用途 ...

    反射

    概述

    定义

    Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。

    用途

    通过反射,Java 代码可以发现有关已加载类的字段,方法和构造函数的信息,并可以在安全限制内对这些字段,方法和构造函数进行操作。

    很多人都认为反射在实际Java中开发应用中并不广泛,其实不然。当我们在使用 IDE(如 IDEA/Eclipse)时,当我们输入一个对象或者类并调用它的属性和方法时,一按 (“.”)点号,编译器就会自动列出她的属性或方法,这里就会用到反射。

    反射最重要的用途就是开发各种通用框架

    很多框架(比如 Spring)都是配置化的(比如Spring 通过 XML 配置模式装载 Bean),为了保证框架的通用性,他们可能根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。

    对于框架开发人员来说,反射作用非常大,它是各种容器实现的核心。而对于一般的开发者来说,不深入框架开发反射用的就会少一点,不过了解一下框架的底层机制有助于丰富自己的编程思想,也是很有益的。

    Java反射框架提供一下功能:

    • 在运行时判定任意一个对象所属的类
    • 在运行时构造任意一个类的对象
    • 在运行时判定任意一个类所具有的成员变量和方法
    • 在运行时调用任意一个对象的方法

    反射的优缺点

    反射的优点

    使用反射机制,代码可以在运行时装配,提高了程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需硬编码目标类

    反射的缺点

    性能问题:使用反射基本上是一种解释操作,JVM无法对这些代码进行优化,因此,反射操作的效率要比那些非反射操作低得多。反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,对性能要求高的程序中不建议使用

    安全限制:使用反射技术要求程序必须在一个没有安全限制的环境中运行

    内部暴露:由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用——代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

    反射机制的相关类

    与Java反射相关的类如下:

    类名 用途
    Class类 代表类的实体,在运行的Java应用程序中表示类和接口
    Field类 代表类的成员变量(成员变量也称为类的属性)
    Method类 代表类的方法
    Constructor类 代表类的构造方法

    Class类

    Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,这里对他们简单的分类介绍。

    • 获得类相关的方法
    方法 用途
    asSubclass(Class clazz) 把传递的类的对象转换成代表其子类的对象
    Cast 把对象转换成代表类或是接口的对象
    getClassLoader() 获得类的加载器
    getClasses() 返回一个数组,数组中包含该类中所有公共类和接口类的对象
    getDeclaredClasses() 返回一个数组,数组中包含该类中所有类和接口类的对象
    forName(String className) 根据类名返回类的对象
    getName() 获得类的完整路径名字
    newInstance() 创建类的实例
    getPackage() 获得类的包
    getSimpleName() 获得类的名字
    getSuperclass() 获得当前类继承的父类的名字
    getInterfaces() 获得当前类实现的类或是接口
    • 获得类中属性相关的方法
    方法 用途
    getField(String name) 获得某个公有的属性对象
    getFields() 获得所有公有的属性对象
    getDeclaredField(String name) 获得某个属性对象
    getDeclaredFields() 获得所有属性对象
    • 获得类中注解相关的方法
    方法 用途
    getAnnotation(Class annotationClass) 返回该类中与参数类型匹配的公有注解对象
    getAnnotations() 返回该类所有的公有注解对象
    getDeclaredAnnotation(Class annotationClass) 返回该类中与参数类型匹配的所有注解对象
    getDeclaredAnnotations() 返回该类所有的注解对象
    • 获得类中构造器相关的方法
    方法 用途
    getConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的公有构造方法
    getConstructors() 获得该类的所有公有构造方法
    getDeclaredConstructor(Class…<?> parameterTypes) 获得该类中与参数类型匹配的构造方法
    getDeclaredConstructors() 获得该类所有构造方法
    • 获得类中方法相关的方法
    方法 用途
    getMethod(String name, Class…<?> parameterTypes) 获得该类某个公有的方法
    getMethods() 获得该类所有公有的方法
    getDeclaredMethod(String name, Class…<?> parameterTypes) 获得该类某个方法
    getDeclaredMethods() 获得该类所有方法
    • 类中其他重要的方法
    方法 用途
    isAnnotation() 如果是注解类型则返回true
    isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果是指定类型注解类型则返回true
    isAnonymousClass() 如果是匿名类则返回true
    isArray() 如果是一个数组类则返回true
    isEnum() 如果是枚举类则返回true
    isInstance(Object obj) 如果obj是该类的实例则返回true
    isInterface() 如果是接口类则返回true
    isLocalClass() 如果是局部类则返回true
    isMemberClass() 如果是内部类则返回true

    Field类

    Field代表类的成员变量(成员变量也称为类的属性)。

    方法 用途
    equals(Object obj) 属性与obj相等则返回true
    get(Object obj) 获得obj中对应的属性值
    set(Object obj, Object value) 设置obj中对应属性值

    Method类

    Method代表类的方法。

    方法 用途
    invoke(Object obj, Object… args) 传递object对象及参数调用该对象对应的方法

    Constructor类

    Constructor代表类的构造方法。

    方法 用途
    newInstance(Object… initargs) 根据传递的参数创建类的对象

    示例

    为了演示反射的使用,首先构造一个与书籍相关的model——Book.java,然后了解获取Class类对象的三种方法,最后通过反射方法示例创建对象、反射私有构造方法、反射私有属性、反射私有方法

    被反射类Book.java

    public class Book{
        private final static String TAG = "BookTag";
    
        private String name;
        private String author;
    
        @Override
        public String toString() {
            return "Book{" +
                    "name='" + name + '\'' +
                    ", author='" + author + '\'' +
                    '}';
        }
    
        public Book() {
        }
    
        private Book(String name, String author) {
            this.name = name;
            this.author = author;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAuthor() {
            return author;
        }
    
        public void setAuthor(String author) {
            this.author = author;
        }
    
        private String declaredMethod(int index) {
            String string = null;
            switch (index) {
                case 0:
                    string = "I am declaredMethod 0 !";
                    break;
                case 1:
                    string = "I am declaredMethod 1 !";
                    break;
                default:
                    string = "I am declaredMethod -1 !";
            }
    
            return string;
        }
    }
    

    获取Class类对象的三种方法

    在反射中,要获取一个类或调用一个类的方法,我们首先需要获取到该类的 Class 对象。
    在 Java API 中,获取 Class 类对象的三种方法
    方法一:使用 Class.forName 静态方法。当你知道该类的全路径名时,你可以使用该方法获取 Class 类对象。但可能抛出 ClassNotFoundException 异常
    Class<?> classBook = Class.forName(“com.jourwon.reflect.Book”);

    方法二:这种方法只适合在编译前就知道操作的 Class。直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高,这说明任何一个类都有一个隐含的静态成员变量 class
    Class clz = Book.class;

    方法三:使用类对象的 getClass() 方法。
    Book book1 = new Book();
    Class<? extends Book> book1Class = book1.getClass();

    @Test
    public void getClz() {
        try {
            // 方法一,使用 Class.forName 静态方法
            Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
    
            // 方法二:直接通过 类名.class 的方式得到
            Class clz = Book.class;
    
            // 方法三:使用类对象的 getClass() 方法。
            Book book1 = new Book();
            Class<? extends Book> book1Class = book1.getClass();
    
            System.out.println(classBook == clz);
            System.out.println(classBook == book1Class);
    
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    

    输出结果都是true,可以知道三种方法获取到的Class对象都是同一个对象

    true
    true
    

    反射常用类和方法测试

    public class ReflectClass {
    
        private static final Logger log = LoggerFactory.getLogger(ReflectClass.class);
    
        // 创建对象
        @Test
        public void reflectNewInstance() {
            try {
                Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
    
                Object objectBook = classBook.newInstance();
                Book book = (Book) objectBook;
                book.setName("Java高级特性-反射-创建对象");
                book.setAuthor("JourWon");
                log.info(book.toString());
    
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    
        // 反射私有的构造方法
        @Test
        public void reflectPrivateConstructor() {
            try {
                Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
                Constructor<?> declaredConstructorBook = classBook.getDeclaredConstructor(String.class, String.class);
                // 暴力反射
                declaredConstructorBook.setAccessible(true);
                Object objectBook = declaredConstructorBook.newInstance("Java高级特性-反射-反射私有的构造方法", "JourWon");
                Book book = (Book) objectBook;
                log.info(book.toString());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    
        // 反射私有属性
        @Test
        public void reflectPrivateField() {
            try {
                Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
                Object objectBook = classBook.newInstance();
                Field fieldTag = classBook.getDeclaredField("TAG");
                fieldTag.setAccessible(true);
                String tag = (String) fieldTag.get(objectBook);
                log.info(tag);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    
    
        // 反射私有方法
        @Test
        public void reflectPrivateMethod() {
            try {
                Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
                Method methodBook = classBook.getDeclaredMethod("declaredMethod", int.class);
                methodBook.setAccessible(true);
                Object objectBook = classBook.newInstance();
                String string = (String) methodBook.invoke(objectBook, 0);
    
                ReflectClass.
    
                log.info(string);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    
    
    }
    

    输出结果

    [main] INFO com.jourwon.reflect.ReflectClass - Book{name='Java高级特性-反射-创建对象', author='JourWon'}
    
    [main] INFO com.jourwon.reflect.ReflectClass - Book{name='Java高级特性-反射-反射私有的构造方法', author='JourWon'}
    
    [main] INFO com.jourwon.reflect.ReflectClass - BookTag
    
    [main] INFO com.jourwon.reflect.ReflectClass - I am declaredMethod 0 ! 
    

    通过反射获取私有属性,方法和构造方法时,需要进行暴力反射,设置setAccessible(true)。否则会报错说无法获取私有属性,方法和构造方法

    总结

    本文列举了反射机制使用过程中常用的、重要的一些类及其方法,更多信息和用法,反射原理和源码分析需要近一步的阅读反射相关资料。

    在阅读Class类文档时发现一个特点,以通过反射获得Method对象为例,一般会提供四种方法,getMethod(parameterTypes)、getMethods()、getDeclaredMethod(parameterTypes)和getDeclaredMethods()。getMethod(parameterTypes)用来获取某个公有的方法的对象,getMethods()获得该类所有公有的方法,getDeclaredMethod(parameterTypes)获得该类某个方法,getDeclaredMethods()获得该类所有方法。带有Declared修饰的方法可以反射到私有的方法,没有Declared修饰的只能用来反射公有的方法。其他的Annotation、Field、Constructor也是如此。

    展开全文
  • java反射

    千次阅读 2018-01-23 18:02:05
    java反射 java反射以及复制一个bean的值到另一个bean中。 深入理解Java反射 https://www.cnblogs.com/luoxn28/p/5686794.html java 使用BeanInfo实现bean实体与map之间的互相转换 ...

    ##java反射

    java反射以及复制一个bean的值到另一个bean中。
    ##深入理解Java反射
    https://www.cnblogs.com/luoxn28/p/5686794.html

    java 使用BeanInfo实现bean实体与map之间的互相转换

    http://blog.csdn.net/cuiyaoqiang/article/details/53582382

    展开全文
  • java 反射

    千次阅读 2016-07-28 16:50:30
    不管咋样,学java的,了解java反射非常有必要!什么是反射反射定义java官方文档给出了解释: Reflection is the ability of a program to query and modify its state during the execution. 意为:反射是在程序运行...

    使用场景

    web中我不太清楚,android中,热修复时的原理,其实就是用的java反射,但不管咋样,学java的,了解java反射非常有必要!

    什么是反射

    反射定义

    java官方文档给出了解释:

    Reflection is the ability of a program to query and modify its state during the execution.

    意为:反射是在程序运行时,能动态查看和修改它的状态。
    在java中,我们能在程序运行时,获取它的属性,方法,修饰符,以及此类的父类。我们也能够在程序运行时,创建一个未知类的实例,并且设置或获取它的属性方法。
    但是,在java中,我们不能在运行时改变它的数据结构,比如说,我们不能在程序运行时,往一个类或者对象里添加新的方法,也不能改变类中方法的代码。

    反射API

    反射中经常用到的几个类,如下所示:

    类名 描述
    java.lang.Class 表示在JVM中被类加载器加载的类。
    java.lang.reflect.Field 表示一个类或者接口的属性。
    java.lang.reflect.Constructor 表示一个类中的构造方法。
    java.lang.reflect.Method 表示一个类或者接口中的方法。
    java.lang.reflect.Modifier 解码一个类及其成员的访问修饰符。
    java.lang.reflect.Array 程序运行时创建数组。

    具体用途

    1. 获取对象类名;
    2. 获取包名,修饰符等等;
    3. 获取类中定义的方法,返回类型,修饰符,参数类型,参数名等等;
    4. 获取所有构造函数;
    5. 用它其中一个构造方法创建类;
    6. 通过方法名和方法参数类型调用方法;
    7. 在运行时动态创建数组,并动态操作此数组元素。

    反射相关类的使用

    java.lang.Class

    先上代码:

    package com.lxh;
    
    public class MyClass {
        static {
            System.out.println("Loading class MyClass...");
        }
    }
    package com.lxh;
    public class Main {
        public static void main(String[] args) {
            try {
                String className = "com.lxh.MyClass";
                boolean initialize = false;
    
                ClassLoader cLoader = Main.class.getClassLoader();
                Class c = Class.forName(className, initialize, cLoader);
                className = "com.lxh.MyClass";
                System.out.println("about to load");
                // Will load and initialize the class
                c = Class.forName(className, true, cLoader);
            } catch (ClassNotFoundException e) {
                System.out.println(e.getMessage());
            }
        }
    }

    log如下:

    about to load
    Loading class MyClass...

    Class.forName(String name, boolean initialize, ClassLoader loader)如果布尔值为false,表示不初始化名为name的类,当为true时,就会初始化。Class.forName(String name)其实也是调用的Class.forName(String name, boolean initialize, ClassLoader loader),只不过它中间默认的布尔值为true。当调用名为name的类时,name类中的静态代码块被加载。
    注意:这里第一个参数name,必须是类的全名,包含包名,否则将调用不到该类。

    java.lang.reflect.Field

    反射类Field表示类中的属性,Field中有如下几种方法:

    Field[] getFields()
    Field[] getDeclaredFields()
    Field getField(String name)
    Field getDeclaredField(String name)

    getFields()表示所有该类所有修饰符为public的属性,以及该类所继承的父类所有修饰符为public的属性。
    getDeclaredFields()表示该类任何修饰符的所有属性,但不包括父类中属性。
    上代码:

    class MySuperClass {
        public int super_id = -1;
        private String super_name = "Unknown";
    }
    
    class MyClass extends MySuperClass{
        private int id = -1;
        public String name = "Unknown";
    }
    
    public class Main {
        public static void main(String[] args) {
            Class<MyClass> c = MyClass.class;
    
            // 获取MyClass类中所有的属性
            ArrayList<String> fieldsDesciption = getDeclaredFieldsList(c);
    
            System.out.println("Declared Fields for " + c.getName());
            for (String desc : fieldsDesciption) {
                System.out.println(desc);
            }
            //获取MyClass类中修饰符为public,及其父类中属性
            fieldsDesciption = getFieldsList(c);
    
            System.out.println("\nAccessible Fields for " + c.getName());
            for (String desc : fieldsDesciption) {
                System.out.println(desc);
            }
        }
    
        public static ArrayList<String> getFieldsList(Class c) {
            Field[] fields = c.getFields();
            ArrayList<String> fieldsList = getFieldsDesciption(fields);
            return fieldsList;
        }
    
        public static ArrayList<String> getDeclaredFieldsList(Class c) {
            Field[] fields = c.getDeclaredFields();
            ArrayList<String> fieldsList = getFieldsDesciption(fields);
            return fieldsList;
        }
    
        public static ArrayList<String> getFieldsDesciption(Field[] fields) {
            ArrayList<String> fieldList = new ArrayList<>();
    
            for (Field f : fields) {
                int mod = f.getModifiers() & Modifier.fieldModifiers();
                //获取该属性的修饰符 public,int等等
                String modifiers = Modifier.toString(mod);
                //获取该属性的类型 int,String等等
                Class<?> type = f.getType();
                String typeName = type.getSimpleName();
                // 获取该属性名
                String fieldName = f.getName();
                //拼接后加到集合中
                fieldList.add(modifiers + "  " + typeName + "  " + fieldName);
            }
            return fieldList;
        }
    }

    打印的log如下:

    Declared Fields for com.lxh.MyClass
    private  int  id
    public  String  name
    
    Accessible Fields for com.lxh.MyClass
    public  String  name
    public  int  super_id

    说明getDeclaredFields()
    获取到了指定类中所有属性,而getFields()获取的是指定类及其父类中修饰符为public的属性。而我们在具体情境下,一般是用getDeclaredFields()方法比较多~

    java.lang.reflect.Method

    Method中有如下方法:

    Method[]  getMethods()
    Method[]  getDeclaredMethods()
    Method getMethod(String name,  Class...  parameterTypes)
    Method getDeclaredMethod(String name,  Class...  parameterTypes)

    跟Field类似,getMethods()返回该类中任何修饰符的方法,getDeclaredMethods()返回该类及其父类中修饰符为public的方法
    上代码:

    class MyClass<T> {
    
      public MyClass(int i, int j, String s) {
    
      }
    
      public MyClass(T t) {
    
      }
    
      public int getInt(String a) {
        return 0;
      }
    }
    
    public class Main {
      public static void main(String[] args) {
        Class<MyClass> c = MyClass.class;
    
        ArrayList<String> methodsDesciption = getDeclaredMethodsList(c);
        System.out.println("Declared Methods  for " + c.getName());
        for (String desc : methodsDesciption) {
          System.out.println(desc);
        }
        methodsDesciption = getMethodsList(c);
        System.out.println("\nMethods for  " + c.getName());
        for (String desc : methodsDesciption) {
          System.out.println(desc);
        }
    
      }
    
      public static ArrayList<String> getMethodsList(Class c) {
        Method[] methods = c.getMethods();
        ArrayList<String> methodsList = getMethodsDesciption(methods);
        return methodsList;
      }
    
      public static ArrayList<String> getDeclaredMethodsList(Class c) {
        Method[] methods = c.getDeclaredMethods();
        ArrayList<String> methodsList = getMethodsDesciption(methods);
        return methodsList;
      }
    
      public static ArrayList<String> getMethodsDesciption(Method[] methods) {
        ArrayList<String> methodList = new ArrayList<>();
    
        for (Method m : methods) {
          String modifiers = getModifiers(m);
    
          Class returnType = m.getReturnType();
          String returnTypeName = returnType.getSimpleName();
    
          String methodName = m.getName();
    
          String params = getParameters(m).toString();
    
          String throwsClause = getExceptionList(m).toString();
    
          methodList.add(modifiers + "  " + returnTypeName + "  " + methodName
              + "(" + params + ") " + throwsClause);
        }
    
        return methodList;
      }
    
      public static ArrayList<String> getParameters(Executable exec) {
        Parameter[] parms = exec.getParameters();
        ArrayList<String> parmList = new ArrayList<>();
        for (int i = 0; i < parms.length; i++) {
    
          int mod = parms[i].getModifiers() & Modifier.parameterModifiers();
          String modifiers = Modifier.toString(mod);
          String parmType = parms[i].getType().getSimpleName();
          String parmName = parms[i].getName();
          String temp = modifiers + "  " + parmType + "  " + parmName;
          if (temp.trim().length() == 0) {
            continue;
          }
          parmList.add(temp.trim());
        }
        return parmList;
      }
    
      public static ArrayList<String> getExceptionList(Executable exec) {
        ArrayList<String> exceptionList = new ArrayList<>();
        for (Class<?> c : exec.getExceptionTypes()) {
          exceptionList.add(c.getSimpleName());
        }
        return exceptionList;
      }
    
      public static String getModifiers(Executable exec) {
        int mod = exec.getModifiers();
        if (exec instanceof Method) {
          mod = mod & Modifier.methodModifiers();
        } else if (exec instanceof Constructor) {
          mod = mod & Modifier.constructorModifiers();
        }
        return Modifier.toString(mod);
      }
    }

    log打印如下:
    这里写图片描述

    java.lang.reflect.Constructor

    跟Method和Field类似~

    通过反射给方法赋值

    直接上代码:

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    class MyClass {
        public MyClass() {
        }
    
        private String name;
    
        public void setName(String name) {
            this.name = name;
            System.out.println("setName():"+name);
        }
    
        public String getName(){
            return name;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Class<MyClass> myClass = MyClass.class;
            try {
                //通过class.newInstance()实例化对象
                MyClass p = myClass.newInstance();
                //给对象中方法赋值
                Method setName = myClass.getMethod("setName", String.class);
                setName.invoke(p, "luoxiaohui");
                //获取赋值后getName()中的返回值,不需要参数.
                Method getName = myClass.getMethod("getName");
                System.out.println(getName.invoke(p));
            } catch (InstantiationException | IllegalAccessException
                    | NoSuchMethodException | SecurityException | IllegalArgumentException
                    | InvocationTargetException e) {
                System.out.println(e.getMessage());
            }
        }
    }

    注意:getMethod(String methodName,Class… parameterType),第一个参数表示方法名,后面范型表示方法的需要传的值,这里一定要跟原来方法相匹配,有参数就传参数。比如setName()方法需要传字符串型,参数则为String.class,而getName()不需要传。如果多传或者少传参数,将对应不上类中的方法。

    通过反射给属性赋值

    前面我们提到的Field的方法getField()和getDeclaredField(),只是获取属性的修饰符,属性类型,属性名,这里来说说给属性具体赋值。
    上代码:

    import java.lang.reflect.Field;
    class MyClass {
      private String name = "Unknown";
    
      public MyClass() {
      }
    
      public String toString() {
        return "name=" + this.name;
      }
    }
    
    public class Main {
      public static void main(String[] args) {
        Class<MyClass> my = MyClass.class;
        try {
          MyClass p = my.newInstance();
          Field nameField = my.getDeclaredField("name");
          //Field.setAccessible()方法要注意
          nameField.setAccessible(true);
          String nameValue = (String) nameField.get(p);
          System.out.println("Current name is " + nameValue);
          nameField.set(p, "luoxiaohui");
          nameValue = (String) nameField.get(p);
          System.out.println("New name is " + nameValue);
        } catch (InstantiationException | IllegalAccessException
            | NoSuchFieldException | SecurityException | IllegalArgumentException e) {
          System.out.println(e.getMessage());
        }
      }
    }

    注意:在获取到Class的Field属性后,记得调用方法Field.setAccessible(true),这样能保证不管该属性是public,private,还是缺省,都能修改它,如果没调用此方法,则只能修改修饰符为public的属性。

    通过反射扩展数组

    java.lang.reflect.Array中有两个方法

    Object newInstance(Class<?> componentType,  int  arrayLength)
    Object newInstance(Class<?> componentType,  int... dimensions)

    前者表示实例化一个长度为arrayLength的数组,后者表示实例化一个数组矩阵,后者此篇暂时不讲。以前在书上看到说数组实例化后,是不能改变起长度的,不过,通过反射,还是可以滴~
    上代码:

    import java.lang.reflect.Array;
    import java.util.Arrays;
    
    public class Main {
    
        private static int[] ids = new int[2];
    
        public static void main(String[] args) {
            ids = new int[2];
            System.out.println(ids.length);
            System.out.println(Arrays.toString(ids));
            //将已经实例化的数组ids扩展两个单位长度
            ids = (int[]) expandBy(2);
            //给数组中某个对象赋值
            ids[2] = 3;
            ids[0] = 5;
            System.out.println(ids.length);
            System.out.println(Arrays.toString(ids));
        }
    
        public static Object expandBy(int increment) {
            Object newArray = null;
            //获取数组ids的长度
            int oldLength = Array.getLength(ids);
            //定义新的长度
            int newLength = oldLength + increment;
            Class<?> c = ids.getClass();
            //此方法很重要,对实例化数组通过反射扩展其长度
            newArray = Array.newInstance(c.getComponentType(), newLength);
            return newArray;
        }
    }

    log打印如下:

    2
    [0, 0]
    4
    [5, 0, 3, 0]

    数组成功扩展!

    关于java中反射已经讲完,欢迎各位交流指教!

    展开全文
  • JAVA反射

    千次阅读 2018-06-02 17:09:03
    一:百度百科介绍JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的...
  • Java 反射

    千次阅读 2016-09-16 11:12:48
    一、Java 语言的反射机制在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法? 答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能...
  • Java反射有多强? 他拥有这五大神奇功能!

    万次阅读 多人点赞 2020-10-24 08:06:12
    Java反射是什么?Java反射有什么用?Java反射究竟有多方便?让我们一起见证反射的伟大吧!

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 88,967
精华内容 35,586
关键字:

java反射

java 订阅