Java【反射机制】

反射机制的概述

  • 反射指程序可以访问、检测和修改它本身状态获或行为的一种能力。反射使程序代码能装载得到JVM中类的内部信息,这些代码可以在运行时进行装载,在程序运行中动态扩展代码。
  • 在程序运行过程中,对任意一个对象,都能知道这个对象所在类的所有属性和方法,都能调用它人一个方法和访问它任意一个属性,这种动态调用对象方法及动态获取信息的功能称为Java语言的反射机制。

反射机制的功能

  • 在运行时判断任意一个++对象所属的类++。
  • 在运行时构造任意一个++类的对象++。
  • 在运行时判断任意一个++类所具有的成员变量和方法++。
  • 在运行时调用任意一个++对象的方法++。
  • ++生成动态代理++。

工作流程

1、获取目标类 Class 对象

每个类在 JVM 中都有一个与之相关的 Class 对象。可以通过以下方式获取 Class 对象:

①通过类字面量"类名.class":

java 复制代码
Class c1 = String.class;

②通过对象实例:

java 复制代码
Object obj = new Object();  //创建类对象
Class c2 = obj.getClass();  //通过类的getClass()方法获取Class对象

java 复制代码
String str = "Hello";
Class c2 = str.getClass();

③通过静态方法 Class.forName() :

java 复制代码
Class c3 = Class.forName("java.lang.String");
//Class.forName必须是类或接口的全称,包含类名/接口名和包名

2、获取成员信息 :通过 Class 对象,可以获取类的字段、方法、构造函数等信息

3、操作成员:通过反射 API 可以读取和修改字段的值、调用方法以及创建对象。

示例:

java 复制代码
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 {
        // 获取 Class 对象
        Class<?> clazz = Person.class;
        
        // 创建对象
        Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
        Object person = constructor.newInstance("John", 30);
        
        // 访问字段
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true);
        System.out.println("Name: " + nameField.get(person));
        
        // 修改字段
        nameField.set(person, "Doe");
        System.out.println("Updated Name: " + nameField.get(person));
        
        // 调用方法
        Method greetMethod = clazz.getMethod("greet", String.class);
        greetMethod.invoke(person, "World");
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void greet(String message) {
        System.out.println(name + " says: " + message);
    }
}

反射API简介

在JDK类库中,以下类实现了Java的反射机制,其中Class类位于java.lang包中,其余在java.lang.reflect包中。

Class类(核心类)

表示类的对象。提供了方法来获取类的字段、方法、构造函数等。

主要方法

  • getFields():获取所有公共字段。
  • getDeclaredFields():获取所有声明的字段,包括私有字段。
  • getMethods():获取所有公共方法。
  • getDeclaredMethods():获取所有声明的方法,包括私有方法。
  • getConstructors():获取所有公共构造函数。
  • getDeclaredConstructors():获取所有声明的构造函数,包括私有构造函数。
  • getSuperclass():获取类的父类。
  • getInterfaces():获取类实现的所有接口。

Field类

表示类的字段(属性)。提供了访问和修改字段的能力。

主要方法

  • get(Object obj):获取指定对象的字段值。
  • set(Object obj, Object value):设置指定对象的字段值。
  • getType():获取字段的数据类型。
  • getModifiers():获取字段的修饰符(如 public、private)。

Method类

表示类的方法。提供了调用方法的能力。

主要方法

  • invoke(Object obj, Object... args):调用指定对象的方法。
  • getReturnType():获取方法的返回类型。
  • getParameterTypes():获取方法的参数类型。
  • getModifiers():获取方法的修饰符(如 public、private)。

Constructor类

表示类的构造函数。提供了创建对象的能力。

主要方法

  • ewInstance(Object... initargs):创建一个新实例,使用指定的构造函数参数。
  • getParameterTypes():获取构造函数的参数类型。
  • getModifiers():获取构造函数的修饰符(如 public、private)。

Array类

表示类的数组类型。提供动态创建和访问数组元素的各种静态方法。

主要方法

  • newInstance():创建数组对象。
  • s``et():给数组对象的特定元素赋值。
  • get():读取数组的特定元素的值。

Proxy类

负责生成动态代理。

主要方法

  • getProxyClass():创建动态代理类的静态方法。
  • newProxyInstance() :创建动态代理类的示例的静态方法。

示例:

java 复制代码
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;

public class ReflectionExample {

    public static void main(String[] args) throws Exception {
        // 获取 Class 对象
        Class<?> clazz = Car.class;

        // 创建 Car 对象
        Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
        Object car = constructor.newInstance("Toyota", 2020);

        // 访问和修改字段
        Field modelField = clazz.getDeclaredField("model");
        Field yearField = clazz.getDeclaredField("year");
        
        // 设置字段为可访问(如果字段是私有的)
        modelField.setAccessible(true);
        yearField.setAccessible(true);
        
        // 打印原始字段值
        System.out.println("Original Model: " + modelField.get(car));
        System.out.println("Original Year: " + yearField.get(car));
        
        // 修改字段值
        modelField.set(car, "Honda");
        yearField.set(car, 2024);
        
        // 打印修改后的字段值
        System.out.println("Updated Model: " + modelField.get(car));
        System.out.println("Updated Year: " + yearField.get(car));
        
        // 调用方法
        Method startMethod = clazz.getMethod("start");
        startMethod.invoke(car);
    }
}

class Car {
    private String model;
    private int year;

    public Car(String model, int year) {
        this.model = model;
        this.year = year;
    }

    public void start() {
        System.out.println("The " + model + " car of year " + year + " is starting.");
    }
}
相关推荐
guangzhi063319 分钟前
JAVA执行引擎详细介绍
java·jvm
解孔明1 小时前
IDEA2023.1添加java虚拟机启动参数,打开断言
java·开发语言
关关不烦恼1 小时前
【Java数据结构】二叉树
java·开发语言·数据结构
苹果酱05671 小时前
使用 React Testing Library 测试自定义 React Hooks
java·开发语言·spring boot·后端·中间件
好奇的菜鸟1 小时前
Java技术体系:深入理解JDK与JRE及其产品线
java·开发语言
api771 小时前
1688商品详情API返回值中的售后保障与服务信息
java·服务器·前端·javascript·python·spring·pygame
疑惑的杰瑞2 小时前
[乱码]确保命令行窗口与主流集成开发环境(IDE)统一采用UTF-8编码,以规避乱码问题
java·c++·vscode·python·eclipse·sublime text·visual studio
自身就是太阳2 小时前
深入理解 Spring 事务管理及其配置
java·开发语言·数据库·spring
喵手2 小时前
Java零基础-多态详解
java·开发语言·python
麋鹿会飞但不飘2 小时前
EasyExcel拿表头(二级表头)爬坑,invokeHeadMap方法
java·spring boot·excel