• java的反射


    Java反射(Reflection)是一种在运行时检查类、方法、字段等结构的能力,以及在运行时实例化对象、调用方法、访问和修改字段等的能力。反射使得程序可以在运行时获取类的信息,操作类的属性和方法,而不需要在编译时就确定这些操作。

    在Java中,反射主要使用java.lang.reflect包中的类和接口来实现。以下是反射的一些基本概念和用法:

    获取Class对象

    你可以通过以下方式获取Class对象:

    Class<?> clazz = Class.forName("com.example.MyClass");
    
    • 1

    或者通过对象实例获取:

    Class<?> clazz = obj.getClass();
    
    • 1

    获取类的信息
    通过Class对象,你可以获取类的信息,比如类的名称、父类、接口、构造方法、方法、字段等:

    String className = clazz.getName();
    Class<?> superClass = clazz.getSuperclass();
    Constructor<?>[] constructors = clazz.getDeclaredConstructors();
    Method[] methods = clazz.getDeclaredMethods();
    Field[] fields = clazz.getDeclaredFields();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    实例化对象
    你可以使用反射来实例化对象,调用构造方法:

    Constructor<?> constructor = clazz.getConstructor(param1Type, param2Type, ...);
    Object instance = constructor.newInstance(param1, param2, ...);
    
    • 1
    • 2

    调用方法
    你可以使用反射来调用对象的方法:

    Method method = clazz.getDeclaredMethod("methodName", param1Type, param2Type, ...);
    Object result = method.invoke(instance, param1, param2, ...);
    
    • 1
    • 2

    访问和修改字段
    你可以使用反射来访问和修改对象的字段:

    Field field = clazz.getDeclaredField("fieldName");
    field.setAccessible(true); // 设置字段可访问
    Object value = field.get(instance); // 获取字段的值
    field.set(instance, newValue); // 设置字段的值
    
    • 1
    • 2
    • 3
    • 4

    Demo

    public class Person {
        private String name;
        private int age;
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public void sayHello() {
            System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class ReflectionExample {
        public static void main(String[] args) throws Exception {
            // 获取Person类的Class对象
            Class<?> personClass = Class.forName("Person");
    
            // 实例化Person对象
            Constructor<?> constructor = personClass.getConstructor(String.class, int.class);
            Object personInstance = constructor.newInstance("John", 30);
    
            // 调用sayHello方法
            Method sayHelloMethod = personClass.getDeclaredMethod("sayHello");
            sayHelloMethod.invoke(personInstance);
    
            // 访问name字段并修改其值
            Field nameField = personClass.getDeclaredField("name");
            nameField.setAccessible(true); // 设置字段可访问
            String nameValue = (String) nameField.get(personInstance);
            System.out.println("Original name: " + nameValue);
            nameField.set(personInstance, "Alice"); // 修改字段值
            System.out.println("Updated name: " + nameField.get(personInstance));
        }
    }
    
    • 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

    这个示例首先获取了Person类的Class对象,然后使用反射实例化了一个Person对象,调用了其sayHello方法,并访问和修改了name字段的值。请注意,反射需要处理异常,因此需要在方法签名中添加throws Exception。

    这只是一个简单的反射示例,实际应用中可以根据需求进行更复杂的操作。反射通常在需要在运行时动态处理类和对象时使用,但要小心维护代码的可读性和性能。

    在使用反射的时候需要注意的事项:

    • 性能开销:反射操作通常比普通方法调用慢,因为它需要在运行时进行类信息的检查和动态调用。因此,避免在性能敏感的代码中过度使用反射。

    • 异常处理:反射方法可能会抛出ClassNotFoundException、NoSuchMethodException、IllegalAccessException等异常,必须进行适当的异常处理。

    • 访问权限:默认情况下,反射不会遵循Java的访问控制规则,因此可以访问私有方法和字段。但这可能破坏了封装性。通过setAccessible(true)可以解除字段和方法的访问限制,但要小心使用,确保有合法的理由。

    • 类型安全:反射操作可能会导致类型不安全的问题,因为编译器无法检查反射调用的参数和返回值类型。在进行类型转换时要格外小心,使用泛型和instanceof来确保类型安全。

    • 版本兼容性:Java版本之间可能会有反射API的变化,因此在不同的Java版本中,反射代码可能会产生不同的行为。需要注意版本兼容性。

    • 文档和注释:由于反射操作不容易在代码中理解,因此应该为反射代码提供清晰的注释和文档,以便其他开发人员理解和维护。

    • 安全性:反射可以用于执行危险操作,因此需要小心防范潜在的安全风险。在受信任的环境中使用反射通常较为安全,但在受限制的环境中要格外小心。

  • 相关阅读:
    职场题:有一件特别紧急的事,群众要办理,且联系不上领导,你怎么办?(1)
    Arduino驱动BNO055 10轴绝对定向传感器(惯性测量传感器篇)
    【PostgreSQL内核学习(十七)—— (AutoAnalyze)】
    洛谷P3512 [POI2010]PIL-Pilots
    【Kotlin 协程】协程简介 ( 协程概念 | 协程作用 | 创建 Android 工程并进行协程相关配置开发 | 异步任务与协程对比 )
    南大通用GBase8s 常用SQL语句(280)
    ssm823基于ssm的心理预约咨询管理系统的设计与实现+vue
    2022年竞赛打榜,神经网络还是干不过树模型??
    修改Tomcat的默认端口号
    二项分布和泊松分布
  • 原文地址:https://blog.csdn.net/qq_45922256/article/details/133592667