• Java随笔-反射


    概述

    能够分析类能力的程序称为反射。

    • 在运行时构造任意类的对象
    • 在运行时获取或修改任意类所有的方法和属性
    • 在运行时调用任意类的方法和属性

    Class

    反射基于Class,没有Class不谈反射。Class类封装了当前对象对应类所有方法和属性,Class属于类的类,拿到Class就能拿到所有的对应类的方法和属性并做些什么。

    获取Class对象

    获取Class对象方式有三种:

    1. 通过类名.class直接获取。
            // 通过类直接获取
            Class<ReflectTest> reflectTestClass = ReflectTest.class;
            Class<Integer> integerClass = int.class;
            Class<Integer> type = Integer.TYPE;
            
            System.out.println("通过类直接获取00:" + reflectTestClass.getName());
            System.out.println("通过类直接获取01:" + integerClass.getName());
            System.out.println("通过类直接获取02:" + type.getName());
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行:

    通过类直接获取00:ReflectTest
    通过类直接获取01:int
    通过类直接获取02:int
    
    • 1
    • 2
    • 3
    1. 通过对象名.getClass获取。
            ReflectTest reflectTest = new ReflectTest();
            Class<? extends ReflectTest> aClass = reflectTest.getClass();
            System.out.println("通过对象名.getClass()获取:" + aClass.getName());
    
    • 1
    • 2
    • 3

    运行:

    通过对象名.getClass()获取:ReflectTest
    
    • 1
    1. 通过全类名获取。

    Class提供的静态方法:

         */
        @CallerSensitive
        public static Class<?> forName(String className)
                    throws ClassNotFoundException {
            Class<?> caller = Reflection.getCallerClass();
            return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    通过全类名获取类对象。

            String className = "ReflectTest";
            try {
                Class<?> aClass1 = Class.forName(className);
                System.out.println("通过全类名获取:" + aClass1.getName());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行:

    通过全类名获取:ReflectTest
    
    • 1

    判断类的类型与实例

            String className = "ReflectTest";
            try {
                Class<?> aClass1 = Class.forName(className);
                Class<?> aClass2 = Class.forName(className);
                System.out.println(aClass1 == aClass2);
                // 判断是否是某个类的实例
                boolean instance = ReflectTest.class.isInstance(aClass1);
                System.out.println(instance ? "是ReflectTest的实例" : "不是ReflectTest的实例");
                
                // 判断是否是某一个类的类型
                boolean assignableFrom = reflectTestClass.isAssignableFrom(ReflectTest.class);
                System.out.println(assignableFrom ? "是ReflectTest类型" : "不是ReflectTest类型");
    
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    运行:

    true
    不是ReflectTest的实例
    是ReflectTest类型
    
    • 1
    • 2
    • 3

    使用==判断结果为true,是因为没有创建实例,两个对象都指向同一个class文件,所以为true。

    • 通过native方法isInstance()判断是不是某一个类的实列。
        public native boolean isInstance(Object obj);
    
    • 1

    代码中只是根据类名的字符串获取到相对应的类,并没有创建该类的对象,所以返回结果正确。

    • 通过isAssignableFrom()判断是不是某一个类的类型。
      代码中获取的类和ReflectTest肯定是同一类型,所以运行结果无误。

    创建实例

    通过反射创建实例有两种方式:通过调用newInstance()方法创建实例;通过先获取Constructor对象,通过Constructor对象调用newInstance()创建实例。

    public class ReflectTest {
        public ReflectTest() {
            System.out.println("这是ReflectTest的构造");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • newInstance()。
     String className = "ReflectTest";
            try {
                Class<?> aClass1 = Class.forName(className);
                Object newInstance = aClass1.newInstance();
    
                // 判断是否是某个类的实例
                boolean instance = ReflectTest.class.isInstance(newInstance);
                System.out.println(instance ? "是ReflectTest的实例" : "不是ReflectTest的实例");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    运行:

    ReflectTest的实例
    
    • 1
    • 先获取Constructor,再调用newInstance。
            String className = "ReflectTest";
            try {
                Class<?> aClass1 = Class.forName(className);
                // 获取构造
                Constructor<?> constructor = aClass1.getConstructor(ReflectTest.class);
                // 通过构造获取实例
                Object instance1 = constructor.newInstance();
                // 判断是否是某个类的实例
                boolean instance = ReflectTest.class.isInstance(instance1);
                System.out.println(instance ? "是ReflectTest的实例" : "不是ReflectTest的实例");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    运行:
    请添加图片描述
    修改:

            try {
                Class<ReflectTest> aClass1 = ReflectTest.class;
                // 获取所有构造
                Constructor<?>[] constructor = aClass1.getConstructors();
                Object instance1 = constructor[0].newInstance();
                // 判断是否是某个类的实例
                boolean instance = ReflectTest.class.isInstance(instance1);
                System.out.println(instance ? "是ReflectTest的实例" : "不是ReflectTest的实例");
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    运行:

    这是ReflectTest的构造
    是ReflectTest的实例
    
    • 1
    • 2

    除了调用getConstructors()可以得到正确的结果外,调用getConstructor(),getDeclaredConstructor()均出现java.lang.NoSuchMethodException异常,详细原因如下:

    方法描述
    getConstructor(Class… parameterTypes)获取使用特殊参数类型的public构造,包含父类
    getConstructors()获取所有公共构造
    getDeclaredConstructors()获取所有的构造
    getDeclaredConstructor(Class… parameterTypes)获取所有使用特殊参数的构造

    获取成员变量

    public class ReflectTest {
        // 共有
        public String name = "名称";
        // 私有
        private int age = 23;
        // 默认
        boolean female = true;
        // 受保护
        protected double salary = 2022.22;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    获取所有成员变量
         String className = "ReflectTest";
            try {
                // 获取类对象
                Class<?> aClass = Class.forName(className);
                // 获取所有成员变量
                Field[] fields = aClass.getFields();
                for (Field field : fields) {
                    // 打印所有成员变量
                    System.out.println(field);
                    System.out.println(field.getName());
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    结果:

    public java.lang.String ReflectTest.name
    name
    
    • 1
    • 2

    getFields()只能获取公共的成员变量,其他的都无法获取。使用getDeclaredFields()可以获取所有申明的成员变量。

                // 获取所有成员变量
                Field[] fields = aClass.getDeclaredFields();
                for (Field field : fields) {
                    // 打印所有成员变量
                    System.out.println(field);
                    System.out.println(field.getName());
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行:

    public java.lang.String ReflectTest.name
    name
    private int ReflectTest.age
    age
    boolean ReflectTest.female
    female
    protected double ReflectTest.salary
    salary
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    获取成员变量的权限修饰
                // 获取所有成员变量
                Field[] fields = aClass.getDeclaredFields();
                for (Field field : fields) {
                    // 打印所有成员变量
                    System.out.println(field);
                    // 权限修饰
                    System.out.println(field.getModifiers());
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行:

    public java.lang.String ReflectTest.name
    1
    private int ReflectTest.age
    2
    boolean ReflectTest.female
    0
    protected double ReflectTest.salary
    4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    权限与其对应的值。

    权限反射中对应的值
    public1
    private2
    protected4
    default0
    获取成员变量的值

    获取成员变量的值,必须先创建对象,没有对象就没有成员变量。

            try {
                ...
                // 创建实例
                ReflectTest reflectTest = new ReflectTest("test");
                // 获取所有成员变量
                Field[] fields = aClass.getFields();
                for (Field field : fields) {
                    // 打印所有成员变量
                    System.out.println(field);
                    System.out.println(field.getName());
                    System.out.println(field.get(reflectTest));
                }
                ...
             }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    结果:

    这是ReflectTest的构造
    public java.lang.String ReflectTest.name
    name
    名称
    
    • 1
    • 2
    • 3
    • 4

    已经获取到属性name的值“名称”。

    修改公共成员变量的值
          // 获取指定成员变量
                Field nameField = aClass.getField("name");
                // 修改成员变量的值
                nameField.set(reflectTest,"狗子");
                // 输出,检查修改是否成功
                System.out.println(reflectTest.name);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行:

    名称
    狗子
    
    • 1
    • 2

    原来name的值是“名称”,已被修改成“狗子”。

    修改私有成员变量的值
                // 获取指定成员变量
                Field ageField = aClass.getDeclaredField("age");
                // 暴力反射,突破权限限制
                ageField.setAccessible(true);
                // 修改成员变量的值
                ageField.set(reflectTest,18);
                // 输出,检查修改是否成功
                System.out.println(reflectTest.getAge());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行:

    18
    
    • 1

    原来是23,现在修改成18,修改成功。

    访问static变量

    static字段:

    private static String power = "石油";
    
    • 1

    修改字段:

            String className = "ReflectTest";
            try {
                // 获取类对象
                Class<?> aClass = Class.forName(className);
                // 创建实例
                ReflectTest reflectTest = new ReflectTest("test");
                // 获取字段
                Field power = aClass.getDeclaredField("power");
                //
                power.setAccessible(true);
                // 修改
                power.set(reflectTest,"太阳");
                Object obj = power.get(reflectTest);
                System.out.println("static修改后的值:" + obj.toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行:

    static修改后的值:太阳
    
    • 1
    修改final成员

    final字段:

        private final String address = "杭州";
        public void showAddress() {
            System.out.println("final修改后的值:" + address);
        }
    
    • 1
    • 2
    • 3
    • 4

    修改:

            String className = "ReflectTest";
            try {
                // 获取类对象
                Class<?> aClass = Class.forName(className);
                // 创建实例
                ReflectTest reflectTest = new ReflectTest("test");
                // 获取字段
                Field address = aClass.getDeclaredField("address");
                //
                address.setAccessible(true);
                // 修改
                address.set(reflectTest,"武汉");
                // 打印
                reflectTest.showAddress();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行:

    final修改后的值:杭州
    
    • 1

    发现修改失败,因为JVM对final进行了优化,其实是修改成功了,只是打印的那个值没有变化,就是编译的时候打印输出的值已经固定了,和它后来是什么样的没有关系了。即:

    System.out.println("final修改后的值:" + address);
    
    • 1

    被优化成:

    System.out.println("final修改后的值:" + "杭州");
    
    • 1

    所以需要修改完后再取出来进行打印输出。

            // 获取类对象
                Class<?> aClass = Class.forName(className);
                // 创建实例
                ReflectTest reflectTest = new ReflectTest("test");
                // 获取字段
                Field address = aClass.getDeclaredField("address");
                //
                address.setAccessible(true);
                // 修改
                address.set(reflectTest,"武汉");
                // 打印
    //            reflectTest.showAddress();
                // 将修改的字段单独取出来进行输出
                Object obj = address.get(reflectTest);
                System.out.println("final修改后的值:" + obj.toString());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    运行:

    final修改后的值:武汉
    
    • 1
    修改static final字段

    static final 字段:

    private static final String area = "西北";
    
    • 1

    修改:

            String className = "ReflectTest";
            try {
                // 获取类对象
                Class<?> aClass = Class.forName(className);
                // 创建实例
                ReflectTest reflectTest = new ReflectTest("test");
                // 获取字段
                Field area = aClass.getDeclaredField("area");
                //
                area.setAccessible(true);
                // 修改
                area.set(reflectTest,"东北");
                Object obj = area.get(reflectTest);
                System.out.println("static final修改后的值:" + obj.toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行:
    在这里插入图片描述
    修正:修改时需要先把final修饰符拿掉,修改完后再把final修饰符加上去。

            String className = "ReflectTest";
            try {
                // 获取类对象
                Class<?> aClass = Class.forName(className);
                // 创建实例
                ReflectTest reflectTest = new ReflectTest("test");
                // 获取字段
                Field area = aClass.getDeclaredField("area");
                //
                area.setAccessible(true);
                // 获取final修饰符
                Field modifiers = area.getClass().getDeclaredField("modifiers");
                // 暴力反射
                modifiers.setAccessible(true);
                // 拿掉final修饰符
                modifiers.setInt(area,area.getModifiers() &~Modifier.FINAL);
                // 修改
                area.set(reflectTest,"东北");
                // 添加final修饰符
                modifiers.setInt(area,area.getModifiers() &~Modifier.FINAL);
                Object obj = area.get(reflectTest);
                System.out.println("static final修改后的值:" + obj.toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    运行:

    static final修改后的值:东北
    
    • 1

    获取方法

    public class ReflectTest {
        public int getAge() {
            return age;
        }
    
        // 私有方法
        private void reflectMethod01(){
        }
    
        // 共有方法
        public void reflectMethod02(){
        }
    
        // 共有带参方法
        public void reflectMethod03(String param){
        }
    
        // 共有带参带返回值的方法
        public String reflectMethod04(String param){
            System.out.println("参数:" + param);
            return param;
        }
        public ReflectTest(String aaa) {
            System.out.println("这是ReflectTest的构造");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    获取所有声明的方法
            try {
                // 获取类对象
                Class<?> aClass = Class.forName(className);
                // 创建实例
                //ReflectTest reflectTest = new ReflectTest("test");
                // 获取所有方法
                Method[] methods = aClass.getDeclaredMethods();
                for (Method mothod : methods) {
                    // 打印所有方法
                    System.out.println(mothod);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    运行:

    public int ReflectTest.getAge()
    public void ReflectTest.reflectMethod02()
    public void ReflectTest.reflectMethod03(java.lang.String)
    private void ReflectTest.reflectMethod01()
    public java.lang.String ReflectTest.reflectMethod04(java.lang.String)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    没有返回构造方法,因为构造方法有单独的方法进行调用,这里不用。

    方法描述
    getDeclaredMethods()返回所有成员方法,不包括继承的
    getDeclaredMethod(String name, Class… parameterTypes)返回某一个具体的成员方法
    getMethods()返回所有公共成员方法,包括继承的
    getMethod(String name, Class… parameterTypes)返回某一个指定的成员方法
    调用公共成员方法

    成员方法:

        // 共有带参带返回值的方法
        public String reflectMethod04(String param){
            System.out.println("参数:" + param);
            return param;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    反射调用成员方法。

                // 获取方法
                Method reflectMethod04 = aClass.getMethod("reflectMethod04", String.class);
                // 调用方法并获取返回值
                Object returnValue = reflectMethod04.invoke(reflectTest, "happy");
                // 打印返回值
                System.out.println("成员方法返回值:" + returnValue);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行:

    参数:happy
    成员方法返回值:happy
    
    • 1
    • 2
    调用私有成员变量

    成员方法:

        // 私有方法
        private void reflectMethod01(){
            System.out.println("这个是私有成员方法");
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    反射调用私有成员方法

                Method reflectMethod01 = aClass.getDeclaredMethod("reflectMethod01");
                // 暴力反射,突破权限
                reflectMethod01.setAccessible(true);
                // 调用方法
                reflectMethod01.invoke(reflectTest);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行:

    这个是私有成员方法
    
    • 1
  • 相关阅读:
    【机器学习入门项目10例】(九):聚类算法用于降维,KMeans的矢量量化应用(图片压缩)
    Cmake用户交互指南
    十年耕耘,致力于让垂直领域合作企业提升竞争力
    【毕业设计】机器学习驾驶疲劳检测系统 - python
    2022秋冬穿搭趋势!小红书榜单,挖掘4大时髦模式
    2022/8/9
    使用C语言实现二叉树的链式存储
    dpdk/spdk/网络协议栈/存储/网关开发/网络安全/虚拟化/ 0vS/TRex/dpvs技术专家成长体系教程
    我的master节点是好的,现在是第一个node1节点利用master节点给出的加入的代码结果报错,如何解决?(标签-kubernetes)
    【python基础】模块和包
  • 原文地址:https://blog.csdn.net/qq_34202054/article/details/123241331