当前位置: 首页 > web >正文

Day(23)--反射

反射

反射允许对成员变量,成员方法和构造方法的信息进行编程访问

获取class对象

  1. Class.forName("全类名");

    全类名 = 包名 + 类名

  2. 类名.class

  3. 对象.getClass();

利用反射获取构造方法

在 Java 里,反射机制可以让你在运行时获取类的信息,其中就包含构造方法。下面我会给出一个示例代码,展示怎样通过反射获取构造方法。

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
​
class MyClass {// 无参构造方法public MyClass() {System.out.println("调用无参构造方法");}
​// 有参构造方法public MyClass(String message) {System.out.println("调用有参构造方法,参数为: " + message);}
}
​
public class ReflectionConstructorExample {public static void main(String[] args) {try {// 获取类的 Class 对象Class<?> clazz = MyClass.class;
​// 获取所有公共构造方法Constructor<?>[] constructors = clazz.getConstructors();
​// 输出所有公共构造方法System.out.println("所有公共构造方法:");for (Constructor<?> constructor : constructors) {System.out.println(constructor);}
​// 获取无参构造方法Constructor<?> noArgConstructor = clazz.getConstructor();// 使用无参构造方法创建对象MyClass obj1 = (MyClass) noArgConstructor.newInstance();
​// 获取有参构造方法Constructor<?> argConstructor = clazz.getConstructor(String.class);// 使用有参构造方法创建对象MyClass obj2 = (MyClass) argConstructor.newInstance("Hello, Reflection!");
​} catch (NoSuchMethodException | InstantiationException |IllegalAccessException | InvocationTargetException e) {e.printStackTrace();}}
}    

代码解释

  1. MyClass:定义了一个类,包含无参构造方法和有参构造方法。

  2. ReflectionConstructorExample

    • clazz.getConstructors():获取类的所有公共构造方法。

    • clazz.getConstructor():获取无参构造方法。

    • clazz.getConstructor(String.class):获取带有一个 String 类型参数的构造方法。

    • constructor.newInstance():使用构造方法创建对象。

注意事项

  • 若要获取非公共的构造方法,可使用 getDeclaredConstructors()getDeclaredConstructor() 方法。

  • 在使用 newInstance() 方法创建对象时,可能会抛出 InstantiationExceptionIllegalAccessExceptionInvocationTargetException 异常,需要进行异常处理。

利用反射获取成员变量

在 Java 中,通过反射机制能够在运行时获取类的成员变量。下面给出示例代码,展示如何使用反射来获取成员变量:

import java.lang.reflect.Field;
​
class Student {// 公共成员变量public String name;// 私有成员变量private int age;// 受保护成员变量protected String gender;
​public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}
}
​
public class ReflectionFieldExample {public static void main(String[] args) {try {// 获取 Student 类的 Class 对象Class<?> studentClass = Student.class;
​// 创建 Student 类的实例Student student = new Student("Alice", 20, "Female");
​// 获取所有公共成员变量Field[] publicFields = studentClass.getFields();System.out.println("所有公共成员变量:");for (Field field : publicFields) {System.out.println(field.getName() + " : " +()); field.getType// 获取公共成员变量的值System.out.println("值为: " + field.get(student));}
​// 获取所有声明的成员变量(包括私有、受保护和公共的)Field[] declaredFields = studentClass.getDeclaredFields();System.out.println("\n所有声明的成员变量:");for (Field field : declaredFields) {System.out.println(field.getName() + " : " + field.getType());// 如果是私有成员变量,需要设置可访问性if (!field.isAccessible()) {field.setAccessible(true);}// 获取成员变量的值System.out.println("值为: " + field.get(student));}
​} catch (IllegalAccessException e) {e.printStackTrace();}}
}    

代码解释

  1. Student:定义了一个包含公共、私有和受保护成员变量的类,并且提供了一个构造方法用于初始化这些变量。

  2. ReflectionFieldExample

    • studentClass.getFields():获取类的所有公共成员变量。

    • studentClass.getDeclaredFields():获取类声明的所有成员变量,包括私有、受保护和公共的。

    • field.get(student):获取指定对象中该成员变量的值。对于私有成员变量,需要先调用 field.setAccessible(true) 来设置可访问性。

注意事项

  • getFields() 方法只能获取公共的成员变量,而 getDeclaredFields() 方法可以获取类中声明的所有成员变量。

  • 访问私有成员变量时,需要调用 setAccessible(true) 方法来绕过 Java 的访问控制检查,但这可能会破坏类的封装性,使用时要谨慎。

反射获取成员方法

在 Java 里,借助反射机制可以在运行时获取类的成员方法。下面是一个示例代码,展示如何通过反射获取成员方法并调用它们:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
​
class Calculator {// 无参方法public int add() {return 1 + 2;}
​// 有参方法public int multiply(int a, int b) {return a * b;}
}
​
public class ReflectionMethodExample {public static void main(String[] args) {try {// 获取 Calculator 类的 Class 对象Class<?> calculatorClass = Calculator.class;
​// 创建 Calculator 类的实例Calculator calculator = calculatorClass.getDeclaredConstructor().newInstance();
​// 获取无参方法Method addMethod = calculatorClass.getMethod("add");// 调用无参方法int result1 = (int) addMethod.invoke(calculator);System.out.println("无参方法 add 的结果: " + result1);
​// 获取有参方法Method multiplyMethod = calculatorClass.getMethod("multiply", int.class, int.class);// 调用有参方法int result2 = (int) multiplyMethod.invoke(calculator, 3, 4);System.out.println("有参方法 multiply 的结果: " + result2);
​} catch (NoSuchMethodException | InstantiationException |IllegalAccessException | InvocationTargetException e) {e.printStackTrace();}}
}    

代码解释

  1. Calculator:定义了两个方法,一个是无参的 add 方法,另一个是带有两个 int 类型参数的 multiply 方法。

  2. ReflectionMethodExample

    • calculatorClass.getMethod("add"):获取名为 add 的无参公共方法。

    • calculatorClass.getMethod("multiply", int.class, int.class):获取名为 multiply 且参数类型为两个 int 类型的公共方法。

    • method.invoke(calculator, ...):调用指定对象的方法。对于无参方法,直接传入对象;对于有参方法,需要传入对象和相应的参数。

注意事项

  • getMethod 方法只能获取公共方法,如果要获取非公共方法,可以使用 getDeclaredMethod 方法。

  • 在调用 invoke 方法时,可能会抛出 InvocationTargetException 异常,该异常的 getCause 方法可以获取实际抛出的异常。

  • 若要调用非公共方法,需要先调用 method.setAccessible(true) 来设置可访问性。

反射的作用

反射是 Java 提供的一种强大机制,允许程序在运行时动态地获取类的信息、创建对象、调用方法以及访问和修改成员变量等。下面详细介绍反射的作用:

1. 动态创建对象

在 Java 里,一般情况下创建对象使用 new 关键字,但在某些场景下,在编译时并不知道要创建哪个类的对象,这时反射就能发挥作用。比如,在配置文件中指定类名,程序运行时根据配置文件的内容动态创建对象。

java

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
​
class ExampleClass {public ExampleClass() {System.out.println("ExampleClass 实例已创建");}
}
​
public class DynamicObjectCreation {public static void main(String[] args) {try {Class<?> clazz = Class.forName("ExampleClass");Constructor<?> constructor = clazz.getConstructor();ExampleClass obj = (ExampleClass) constructor.newInstance();} catch (ClassNotFoundException | NoSuchMethodException |InstantiationException | IllegalAccessException |InvocationTargetException e) {e.printStackTrace();}}
}

2. 动态调用方法

借助反射,能够在运行时动态地调用对象的方法。这在框架开发里十分有用,比如在测试框架中,可根据测试用例动态调用相应的测试方法。

java

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
​
class MethodCallExample {public void printMessage(String message) {System.out.println("消息: " + message);}
}
​
public class DynamicMethodCall {public static void main(String[] args) {try {MethodCallExample example = new MethodCallExample();Class<?> clazz = example.getClass();Method method = clazz.getMethod("printMessage", String.class);method.invoke(example, "Hello, Reflection!");} catch (NoSuchMethodException | IllegalAccessException |InvocationTargetException e) {e.printStackTrace();}}
}

3. 访问和修改私有成员

虽然 Java 有访问控制机制来限制对私有成员的访问,但反射可以绕过这些限制,在运行时访问和修改私有成员变量和方法。不过要谨慎使用,因为这可能破坏类的封装性。

java

import java.lang.reflect.Field;
​
class PrivateAccessExample {private String privateField = "私有字段的值";
}
​
public class AccessPrivateMembers {public static void main(String[] args) {try {PrivateAccessExample example = new PrivateAccessExample();Class<?> clazz = example.getClass();Field field = clazz.getDeclaredField("privateField");field.setAccessible(true);String value = (String) field.get(example);System.out.println("私有字段的值: " + value);field.set(example, "新的值");System.out.println("修改后的私有字段的值: " + field.get(example));} catch (NoSuchFieldException | IllegalAccessException e) {e.printStackTrace();}}
}

4. 实现通用的工具类

反射能够用于实现通用的工具类,比如序列化和反序列化工具。通过反射,可以遍历对象的所有字段,将其转换为字节流或者从字节流中恢复对象。

5. 框架开发

众多 Java 框架(如 Spring、Hibernate 等)广泛使用反射机制。例如,Spring 框架通过反射来创建和管理 Bean,根据配置文件或者注解动态地注入依赖。

6. 插件化开发

在插件化开发中,主程序可以通过反射加载和使用插件类,无需在编译时知道插件的具体实现。这样能增强程序的扩展性和灵活性。

综上所述,反射机制为 Java 程序带来了高度的灵活性和可扩展性,不过也存在一些缺点,像性能开销较大、破坏封装性等,所以在使用时要权衡利弊。

http://www.xdnf.cn/news/195.html

相关文章:

  • java的lambda和stream流操作
  • # 使用 PyTorch 构建并训练一个简单的 CNN 模型进行图像分类
  • 推荐一款Umi-OCR_文字识别工具
  • 黑马V11版 最新Java高级软件工程师课程-JavaEE精英进阶课
  • 基于 JSP 的企业财务管理系统:设计、实现与技术解析
  • C++ 面向对象关键语法详解:override、虚函数、转发调用和数组引用传参-策略模式
  • 招商信诺原点安全:一体化数据安全管理解决方案荣获“鑫智奖”!
  • 健康养生指南
  • 51单片机实验六:通用型1602液晶操作方法
  • java 排序算法-快速排序
  • uCOS3实时操作系统(系统架构和中断管理)
  • 【行测】数量关系
  • 医学教育视频会议系统私有化部署方案
  • 抗辐照设计优化:商业航天高可靠系统设计的关键路径
  • Zookeeper介绍与安装配置
  • webgl入门实例-11WebGL 视图矩阵 (View Matrix)基本概念
  • 项目管理基础---引言
  • 进阶篇|CAN FD 与性能优化
  • C# 单例模式
  • 交叉注意力层的实质作用:连接编码器和解码器
  • 【C++】入门基础【上】
  • 【Pandas】pandas DataFrame isin
  • CentOS7执行yum命令报错 Could not retrieve mirrorlist http://mirrorlist.centos.org
  • 使用Java动态数据生成PDF报告:简化您的报告导出流程
  • 利用大模型实现地理领域文档中英文自动化翻译
  • 计算机网络——网络模型
  • 高频面试题:Android MVP/MVVM/MVI这几种架构在实际生产中,各自的优缺点和适用场景是什么
  • Banana Pi BPI-RV2 RISC-V 路由器开发板发售, 全球首款RISC-V路由器
  • Docker设置环境变量
  • 并发设计模式实战系列(2):领导者/追随者模式