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.");
    }
}
相关推荐
自由鬼3 分钟前
正向代理服务器Squid:功能、架构、部署与应用深度解析
java·运维·服务器·程序人生·安全·架构·代理
fouryears_234171 小时前
深入拆解Spring核心思想之一:IoC
java·后端·spring
codervibe1 小时前
使用 Spring Boot + JWT 实现多角色登录认证(附完整流程图)
java·后端
坚持学习永不言弃1 小时前
Ehcache、Caffeine、Memcached和Redis缓存
java
阿劲1 小时前
从业务卡顿到数据库连接池耗尽:Spring Boot项目HikariCP超时问题实战排查
java·后端·面试
亮1111 小时前
Maven 编译过程中发生了 Java Heap Space 内存溢出(OutOfMemoryError)
java·开发语言·maven
添乱1 小时前
「Java案例」求PI的值
java
Zhu_S W2 小时前
深入理解Java虚拟机:Java内存区域与内存溢出异常
java·开发语言·jvm
快乐非自愿2 小时前
商品中心—库存分桶高并发的优化文档
java·前端·spring
鸡蛋灌Bean2 小时前
Java常用设计模式大全
java·开发语言·设计模式