反射和反射的方法

简介: 反射和反射的方法

反射是一种在运行时检查、探知和修改类的能力。通过反射,我们可以在程序运行过程中动态地获取类的信息,并且可以调用类的方法、访问类的属性,甚至可以实例化对象,即使在编译时我们并不知道这些类的存在或者没有对这些类进行硬编码。

在 Java 中,反射使用 java.lang.reflect 包提供的类和接口来实现。常用的反射类包括 ClassMethodFieldConstructor 等。

通过反射,我们可以完成以下一些操作:

  1. 获取类的信息:通过 Class 类可以获取类的名称、包名、父类、接口、注解等信息。
  2. 实例化对象:通过 Class 类的 newInstance() 方法可以创建类的实例,相当于调用了类的无参构造方法
  3. 获取和调用方法:通过 Method 类可以获取类的方法对象,然后可以通过 Method 对象调用相应的方法。
  4. 获取和设置属性:通过 Field 类可以获取类的字段对象,然后可以通过 Field 对象获取或设置相应的属性值。
  5. 调用私有方法和访问私有属性:通过反射,即使方法或字段是私有的,也可以进行访问和调用。

反射在某些场景下非常有用,比如框架和工具的设计与开发,它可以在运行时动态地处理对象和类,增加了程序的灵活性和扩展性。但是反射也会带来一些潜在的问题,比如性能开销较大、可读性较差、对访问权限的限制等,因此在使用反射时需要谨慎权衡利弊。

在 Java 中,通过反射可以获取和操作类的构造方法。构造方法主要用于创建对象实例,因此通过反射可以在运行时动态地实例化对象。下面是一些常用的构造方法相关的反射操作:

  1. 获取构造方法对象:
  • 通过 Class 类的 getConstructor(Class... parameterTypes) 方法可以获取公共的构造方法,需要传入参数类型的数组。
  • 通过 Class 类的 getDeclaredConstructor(Class... parameterTypes) 方法可以获取任意访问权限的构造方法,也需要传入参数类型的数组。
  1. 实例化对象:
  • 获取到构造方法对象后,可以使用 newInstance(Object... initargs) 方法通过构造方法创建对象的实例,需要传入相应的初始化参数。
  1. 调用私有构造方法:
  • 如果要获取并调用私有的构造方法,则需要先通过 setAccessible(true) 方法将构造方法设置为可访问,然后才能调用 newInstance() 方法实例化对象。

下面是一个示例代码,展示了如何通过反射获取构造方法并实例化对象:

import java.lang.reflect.Constructor;
public class ReflectionExample {
    public static void main(String[] args) {
        try {
            // 获取类的Class对象
            Class<?> cls = MyClass.class;
            // 获取公共的构造方法,并实例化对象
            Constructor<?> publicConstructor = cls.getConstructor();
            Object publicObject = publicConstructor.newInstance();
            // 获取私有的构造方法,设置为可访问,并实例化对象
            Constructor<?> privateConstructor = cls.getDeclaredConstructor(int.class);
            privateConstructor.setAccessible(true);
            Object privateObject = privateConstructor.newInstance(123);
            System.out.println("Public object: " + publicObject);
            System.out.println("Private object: " + privateObject);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class MyClass {
    // 公共构造方法
    public MyClass() {
        System.out.println("Public constructor called");
    }
    // 私有构造方法
    private MyClass(int num) {
        System.out.println("Private constructor called with " + num);
    }
}

在上述示例中,通过 getConstructor() 方法获取了 MyClass 类的公共构造方法,并使用 newInstance() 方法实例化了一个对象。然后通过 getDeclaredConstructor() 方法获取了私有构造方法,并使用 setAccessible(true) 设置为可访问,再使用 newInstance() 方法实例化了另一个对象。

需要注意的是,当获取构造方法时,需要根据构造方法的参数类型来选取相应的方法,参数类型可以通过 Class 对象或其它反射相关的方法来获取。同时,在进行反射操作时,需要处理可能抛出的异常,比如 NoSuchMethodExceptionIllegalAccessExceptionInstantiationException 等。

反射获取成员方法

通过反射可以获取类的成员方法,并且可以在运行时动态地调用这些方法。下面是一些常用的成员方法相关的反射操作:

  1. 获取公共方法:
  • 通过 Class 类的 getMethod(String name, Class... parameterTypes) 方法可以获取指定名称和参数类型的公共方法。
  • 通过 Class 类的 getMethods() 方法可以获取所有公共方法的数组。
  1. 获取任意访问权限的方法:
  • 通过 Class 类的 getDeclaredMethod(String name, Class... parameterTypes) 方法可以获取指定名称和参数类型的任意访问权限的方法。
  • 通过 Class 类的 getDeclaredMethods() 方法可以获取所有方法的数组,包括公共方法和非公共方法。
  1. 调用方法:
  • 获取到方法对象后,可以使用 invoke(Object obj, Object... args) 方法调用方法,需要传入对象实例和相应的参数。如果该方法是静态方法,则可以将对象实例设为 null
  1. 调用私有方法:
  • 如果要调用私有方法,则需要先通过 setAccessible(true) 方法将方法设置为可访问,然后才能调用 invoke() 方法。
import java.lang.reflect.Method;
public class ReflectionExample {
    public static void main(String[] args) {
        try {
            // 获取类的Class对象
            Class<?> cls = MyClass.class;
            // 获取公共方法,并调用
            Method publicMethod = cls.getMethod("publicMethod");
            publicMethod.invoke(null);
            // 获取私有方法,设置为可访问,并调用
            Method privateMethod = cls.getDeclaredMethod("privateMethod");
            privateMethod.setAccessible(true);
            privateMethod.invoke(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class MyClass {
    public static void publicMethod() {
        System.out.println("Public method called");
    }
    private static void privateMethod() {
        System.out.println("Private method called");
    }
}
  • 在上述示例中,通过 getMethod() 方法获取了 MyClass 类的公共方法,并使用 invoke() 方法调用了该方法。然后通过 getDeclaredMethod() 方法获取了私有方法,并使用 setAccessible(true) 设置为可访问,再使用 invoke() 方法调用了该方法。
    需要注意的是,在获取方法时,需要根据方法的名称和参数类型来选取相应的方法。对于重载方法,需要确保提供准确匹配的参数类型。同时,在进行反射操作时,需要处理可能抛出的异常,比如 NoSuchMethodExceptionIllegalAccessException 等。

反射获取成员变量

通过反射可以获取类的成员变量,并且可以在运行时动态地访问和修改这些变量的值。下面是一些常用的成员变量相关的反射操作:

  1. 获取公共变量:
  • 通过 Class 类的 getField(String name) 方法可以获取指定名称的公共变量。
  • 通过 Class 类的 getFields() 方法可以获取所有公共变量的数组。
  1. 获取任意访问权限的变量:
  • 通过 Class 类的 getDeclaredField(String name) 方法可以获取指定名称的任意访问权限的变量。
  • 通过 Class 类的 getDeclaredFields() 方法可以获取所有变量的数组,包括公共变量和非公共变量。
  1. 获取和修改变量的值:
  • 获取到变量对象后,可以使用 get(Object obj) 方法获取变量的值,需要传入对象实例。
  • 使用 set(Object obj, Object value) 方法可以修改变量的值,需要传入对象实例和新的值。如果该变量是静态变量,则可以将对象实例设为 null
  1. 获取和设置私有变量:
  • 如果要获取和设置私有变量,则需要先通过 setAccessible(true) 方法将变量设置为可访问,然后才能调用相应的方法。

下面是一个示例代码,展示了如何通过反射获取成员变量并访问和修改其值:

import java.lang.reflect.Field;
public class ReflectionExample {
    public static void main(String[] args) {
        try {
            // 获取类的Class对象
            Class<?> cls = MyClass.class;
            // 获取公共变量,并访问和修改其值
            Field publicField = cls.getField("publicVar");
            System.out.println("Public variable value: " + publicField.get(null));
            publicField.set(null, "New value");
            System.out.println("Updated public variable value: " + publicField.get(null));
            // 获取私有变量,设置为可访问,并访问和修改其值
            Field privateField = cls.getDeclaredField("privateVar");
            privateField.setAccessible(true);
            System.out.println("Private variable value: " + privateField.get(null));
            privateField.set(null, "New value");
            System.out.println("Updated private variable value: " + privateField.get(null));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class MyClass {
    public static String publicVar = "Public value";
    private static String privateVar = "Private value";
}

在上述示例中,通过 getField() 方法获取了 MyClass 类的公共变量,并使用 get() 方法获取该变量的值,同时使用 set() 方法修改了变量的值。然后通过 getDeclaredField() 方法获取了私有变量,并使用 setAccessible(true) 设置为可访问,再次使用 get()set() 方法访问和修改了私有变量的值。

需要注意的是,在获取变量时,需要根据变量的名称来选取相应的变量。同时,在进行反射操作时,需要处理可能抛出的异常,比如 NoSuchFieldExceptionIllegalAccessException 等。


相关文章
|
前端开发 搜索推荐 JavaScript
使用uniapp实现时钟功能
使用uniapp实现时钟功能
539 1
|
安全 vr&ar Python
恒定电流
恒定电流
446 2
|
人工智能 供应链 安全
暸望塔丨三大投入,为中国企业走向全球铺路搭桥
面对新一轮的历史机遇,阿里云将以战略级的投入,为中国企业出海提供一流的基础设施、一流的技术和一流的服务,与最优秀的中国企业在全球并肩前行,共赴新的大航海时代。
暸望塔丨三大投入,为中国企业走向全球铺路搭桥
|
8月前
|
开发者 容器
鸿蒙开发:弹性布局Flex
在实际的开发中,需要掌握主轴与交叉轴的关系、换行规则及子元素属性,同时注意性能与兼容性问题,还有一点,Flex组件在渲染时存在二次布局过程,因此在对性能有严格要求的场景下建议使用Column、Row代替。
232 10
鸿蒙开发:弹性布局Flex
双模态后门攻击框架
本研究提出一种融合数据投毒与模型投毒优势的联邦学习双模态后门攻击框架,通过动态协同攻击机制,在数据层面利用生成对抗网络生成自适应触发器,在模型层面引入梯度伪装机制,实现攻击隐蔽性和持续性突破。实验表明,该方案在CIFAR-10和Fashion-MNIST数据集上攻击成功率提升23.7%,并在20轮模型更新中保持后门功能存活。
|
11月前
|
编解码 IDE KVM
Happy coding,明基RD280U使用分享
最近尝试了明基的专业编程显示器 `RD280U`,28寸4K分辨率,3:2屏幕比例,适合编程。支持硬件级防蓝光、抗反射面板,接口丰富,支持KVM。自动亮度调节、编码模式和软件辅助功能,使其在编程体验上表现出色。如果你对专业编程显示器有需求,这无疑是一个不错的选择。
411 12
|
11月前
|
数据采集 JSON Java
利用Java获取京东SKU接口指南
本文介绍如何使用Java通过京东API获取商品SKU信息。首先,需注册京东开放平台账号并创建应用以获取AppKey和AppSecret。接着,查阅API文档了解调用方法。明确商品ID后,构建请求参数并通过HTTP客户端发送请求。最后,解析返回的JSON数据提取SKU信息。注意遵守API调用频率限制及数据保护法规。此方法适用于电商平台及其他数据获取场景。
|
传感器 编解码 人工智能
为 NVIDIA Jetson 和其他嵌入式系统选择合适的摄像头
本文详细介绍了为NVIDIA Jetson和其他嵌入式系统选择合适摄像头模块的关键因素,包括传感器类型(CCD和CMOS)、电子快门(全局快门和滚动快门)、彩色或单色传感器、动态范围、分辨率、帧率和接口等。文章还提供了光学器件的选择建议,并列出了NVIDIA摄像头模块合作伙伴,帮助用户完成从概念到生产的整个设计过程。
208 0
为 NVIDIA Jetson 和其他嵌入式系统选择合适的摄像头
|
11月前
|
弹性计算 分布式计算 监控
祝贺叠纸新游《无限暖暖》全球开服!阿里云全球基础设施持续护航
祝贺叠纸新游《无限暖暖》全球开服!阿里云全球基础设施持续护航
394 5