一、基础知识
1.1、概念
java 反射(Reflection)是 Java 提供的一种强大的机制,允许程序在运行时动态地获取类的信息(如类名、方法、字段、构造函数等),并操作类的属性、调用类的方法。反射机制广泛应用于框架开发(如 Spring、Hibernate)和动态代理等场景。
1.2、 核心类
Java 反射的核心类位于 java.lang.reflect
包中,主要包括以下类:
Class
:表示一个类或接口,是反射的核心类。Field
:表示类的字段(成员变量)。Method
:表示类的方法。Constructor
:表示类的构造函数。Modifier
:提供对类和成员访问修饰符的解码功能。Annotation
:表示注解类型。Parameter
:表示方法或构造器的参数。
1.3、主要功能
反射的主要功能包括:
- 获取类的信息:如类名、父类、接口、修饰符等。
- 获取类的成员:如字段、方法、构造函数等。
- 操作类的属性:获取或设置字段的值。
- 调用类的方法:动态调用类的方法。
- 创建对象:通过构造函数动态创建对象。
二、 常用方法
2.1、Class 类
2.1.1、详解
方法名 | 功能 |
---|---|
forName(String className) |
根据类的全限定名加载类并返回对应的 Class 对象 |
getName() |
获取类的全限定名 |
getSimpleName() |
获取类的简单名称(不包括包名) |
getSuperclass() |
获取该类的父类,返回 Class<?> 对象 |
getInterfaces() |
获取该类实现的所有接口,返回 Class<?>[] 数组 |
isInterface() |
判断该类是否是一个接口 |
isAnnotation() |
判断该类是否是一个注解 |
isEnum() |
判断该类是否是一个枚举 |
isPrimitive() |
判断某个字段或方法的参数是否为基本数据类型 |
isAssignableFrom(Class<?> cls) |
判断当前类是否是 cls 的父类或接口 |
getMethods() |
获取该类的所有公共方法(包括从父类继承的),返回 Method[] 数组 |
getDeclaredMethods() |
获取该类中声明的所有方法(不包括继承的方法),返回 Method[] 数组 |
getFields() |
获取该类的所有公共字段(包括从父类继承的),返回 Field[] 数组 |
getDeclaredFields() |
获取该类中声明的所有字段(不包括继承的字段),返回 Field[] 数组 |
getConstructors() |
获取该类的所有公共构造器,返回 Constructor<?>[] 数组 |
getDeclaredConstructors() |
获取该类中声明的所有构造器(包括私有构造器),返回 Constructor<?>[] 数组 |
newInstance() |
创建该类的一个新实例(已过时,推荐使用 Constructor.newInstance() ) |
isInstance(Object obj) |
判断指定对象是否是该类的实例 |
isAnnotationPresent(Class<? extends Annotation> annotationClass) |
判断该类是否被指定注解标注 |
getAnnotations() |
获取该类上的所有注解,返回 Annotation[] 数组 |
getAnnotation(Class<T> annotationClass) |
获取该类上的指定注解 |
2.1.2、举例
- 代码
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.Arrays;
public class TestUtil {
// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
String value() default "default_value";
}
// 示例类
@MyAnnotation(value = "测试的注解")
public static class MyClass implements MyInterface {
private String name;
protected int age;
public MyClass() {
}
public MyClass(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public void doSomething() {
System.out.println("Test...");
}
}
public interface MyInterface {
void doSomething();
}
public static void main(String[] args) throws Exception {
// 获取 Class 对象
Class<?> clazz = MyClass.class;
// 获取类的基本信息
System.out.println("全类名: " + clazz.getName());
System.out.println("类名: " + clazz.getSimpleName());
System.out.println("是不是接口: " + clazz.isInterface());
System.out.println("是不是注解: " + clazz.isAnnotation());
System.out.println("是不是枚举: " + clazz.isEnum());
// 获取父类和实现的接口
System.out.println("父类: " + clazz.getSuperclass().getName());
System.out.println("实现的接口: " + Arrays.toString(clazz.getInterfaces()));
// 获取注解
if (clazz.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);
System.out.println("注解 value值: " + annotation.value());
}
// 获取所有公共方法
System.out.println("\n获取所有公共方法:");
for (Method method : clazz.getMethods()) {
System.out.println(method);
}
// 获取所有声明的方法(包括私有方法)
System.out.println("\n获取所有声明的方法(包括私有方法):");
for (Method method : clazz.getDeclaredMethods()) {
System.out.println(method);
}
// 获取所有公共字段
System.out.println("\n获取所有公共字段:");
for (Field field : clazz.getFields()) {
System.out.println(field);
}
// 获取所有声明的字段(包括私有字段)
System.out.println("\n获取所有声明的字段(包括私有字段):");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(field);
}
// 获取所有公共构造器
System.out.println("\n获取所有公共构造器:");
for (Constructor<?> constructor : clazz.getConstructors()) {
System.out.println(constructor);
}
// 获取所有声明的构造器(包括私有构造器)
System.out.println("\n获取所有声明的构造器(包括私有构造器):");
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
System.out.println(constructor);
}
// 创建新实例
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
Object instance = constructor.newInstance("Alice", 25);
// 调用方法
Method setNameMethod = clazz.getMethod("setName", String.class);
setNameMethod.invoke(instance, "Bob");
Method getNameMethod = clazz.getMethod("getName");
String name = (String) getNameMethod.invoke(instance);
System.out.println("\n调用方法修改后的Name值: " + name);
// 访问并修改字段
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); // 设置私有字段可访问
nameField.set(instance, "Charlie");
System.out.println("修改后的name值: " + nameField.get(instance));
}
}
- 结果
2.2、Field 类
2.2.1、详解
方法名 | 作用 |
---|---|
getName() |
获取字段名称 |
getType() |
获取字段类型,返回 Class<?> |
setAccessible(boolean flag) |
设置是否允许访问私有字段 |
get(Object obj) |
获取指定对象中的字段值 |
set(Object obj, Object value) |
设置指定对象中的字段值 |
isAnnotationPresent(Class<? extends Annotation> annotationClass) |
判断该字段是否被指定注解标注 |
getAnnotations() |
获取该字段上的所有注解,返回 Annotation[] 数组 |
getAnnotation(Class<T> annotationClass) |
获取该字段上的指定注解 |
getGenericType() |
获取字段的泛型类型,返回 Type 对象 |
getModifiers() |
获取字段的修饰符,返回整数值(可以通过 Modifier 类解析) |
getBoolean(Object obj) |
获取指定对象上的布尔类型字段值 |
setBoolean(Object obj, boolean value) |
设置指定对象上的布尔类型字段值 |
getByte(Object obj) |
获取指定对象上的字节类型字段值 |
setByte(Object obj, byte value) |
设置指定对象上的字节类型字段值 |
getChar(Object obj) |
获取指定对象上的字符类型字段值 |
setChar(Object obj, char value) |
设置指定对象上的字符类型字段值 |
getShort(Object obj) |
获取指定对象上的短整型字段值 |
setShort(Object obj, short value) |
设置指定对象上的短整型字段值 |
getInt(Object obj) |
获取指定对象上的整型字段值 |
setInt(Object obj, int value) |
设置指定对象上的整型字段值 |
getLong(Object obj) |
获取指定对象上的长整型字段值 |
setLong(Object obj, long value) |
设置指定对象上的长整型字段值 |
getFloat(Object obj) |
获取指定对象上的浮点型字段值 |
setFloat(Object obj, float value) |
设置指定对象上的浮点型字段值 |
getDouble(Object obj) |
获取指定对象上的双精度浮点型字段值 |
setDouble(Object obj, double value) |
设置指定对象上的双精度浮点型字段值 |
2.2.2、举例
- 代码
import java.lang.annotation.*;
import java.lang.reflect.*;
public class TestUtil {
// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyFieldAnnotation {
String value() default "default_value";
int priority() default 1;
}
// 示例类
public static class Person {
@MyFieldAnnotation(value = "名称", priority = 3)
private String name;
@MyFieldAnnotation(value = "年龄", priority = 2)
protected int age;
public double money;
public Person(String name, int age, double money) {
this.name = name;
this.age = age;
this.money = money;
}
@Override
public