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.");
    }
}
相关推荐
夜晚回家33 分钟前
「Java基本语法」代码格式与注释规范
java·开发语言
斯普信云原生组43 分钟前
Docker构建自定义的镜像
java·spring cloud·docker
wangjinjin1801 小时前
使用 IntelliJ IDEA 安装通义灵码(TONGYI Lingma)插件,进行后端 Java Spring Boot 项目的用户用例生成及常见问题处理
java·spring boot·intellij-idea
wtg44521 小时前
使用 Rest-Assured 和 TestNG 进行购物车功能的 API 自动化测试
java
白宇横流学长1 小时前
基于SpringBoot实现的大创管理系统设计与实现【源码+文档】
java·spring boot·后端
fat house cat_2 小时前
【redis】线程IO模型
java·redis
stein_java3 小时前
springMVC-10验证及国际化
java·spring
weixin_478689763 小时前
C++ 对 C 的兼容性
java·c语言·c++
LUCIAZZZ3 小时前
HikariCP数据库连接池原理解析
java·jvm·数据库·spring·springboot·线程池·连接池
sky_ph4 小时前
JAVA-GC浅析(二)G1(Garbage First)回收器
java·后端