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.");
    }
}
相关推荐
devpotato16 分钟前
人工智能(九)- Spring AI MCP客户端开发
java·mcp
疯狂打码的少年24 分钟前
【Day14 Java转Python】从Java到Python——用Python重构一个Java小工具(文件批量重命名实战)
java·python·重构
无籽西瓜a29 分钟前
【西瓜带你学设计模式 | 第十八期 - 命令模式】命令模式 —— 请求封装与撤销实现、优缺点与适用场景
java·后端·设计模式·软件工程·命令模式
aXin_ya32 分钟前
微服务 第二天
java·数据库·微服务
希望永不加班37 分钟前
Spring AOP 核心概念:切面、通知、切点、织入
java·数据库·后端·mysql·spring
lxh011342 分钟前
电话号码的字母组合
java·javascript·算法
爱学习的小可爱卢1 小时前
算法—Java Map 核心方法与实战场景指南
java·开发语言·算法
豆豆1 小时前
建站系统怎么选?2026年SaaS平台与开源CMS对比分析
java·开发语言·开源·cms·网站建设·网站制作·网站开发
鹓于1 小时前
PPT VBA随机选题系统实现详解
java·前端·javascript