目录
一、Method对象详解
Method对象的定义与获取
在Java反射API中,java.lang.reflect.Method
类代表类或接口中声明的一个方法。Method对象封装了方法的完整信息,包括方法名、返回类型、参数类型、异常类型、访问修饰符等,以及用于执行方法的invoke()
方法。
获取Method对象主要有以下两种方式:
通过Class对象的getMethods()
方法获取:此方法返回当前类及其父类中所有public方法的Method对象数组,包括继承自Object类和接口的方法。
Class<?> clazz = SomeClass.class;
Method[] methods = clazz.getMethods();
通过Class对象的getDeclaredMethods()
方法获取:此方法返回当前类中所有声明(包括private、protected、default和public)的方法的Method对象数组,但不包括父类或接口的方法。
Method[] declaredMethods = clazz.getDeclaredMethods();
Method对象的核心方法与应用
调用方法:invoke()
Method
类的invoke()
方法是其最核心的功能,用于在给定的对象上调用该方法,接受两个参数:一个是目标对象(对于静态方法,可以传入null),另一个是方法参数列表(可以是数组形式)。
Method method = clazz.getMethod("methodName", paramTypes...);
Object result = method.invoke(targetObject, methodArgs...);
获取/设置方法访问权限:setAccessible()
当方法为非public且需要在反射中调用时,可以使用setAccessible(true)
来忽略Java语言访问检查,允许对私有、受保护、包访问权限的方法进行访问和调用。
method.setAccessible(true);
获取方法相关信息
- 获取方法返回类型:
method.getReturnType()
返回Class<?>
对象表示方法的返回类型。 - 获取方法参数类型:
method.getParameterTypes()
返回Class<?>[]
数组表示方法参数类型。 - 获取方法异常类型:
method.getExceptionTypes()
返回Class<?>[]
数组表示方法声明抛出的异常类型。 - 获取方法修饰符:
method.getModifiers()
返回整型值表示方法的访问权限修饰符(如public
、private
等),可通过Modifier
类的静态方法进行解析。
处理重载方法
当类中存在同名但参数列表不同的重载方法时,可以通过Class.getMethod(String name, Class<?>... parameterTypes)
方法精确指定方法名和参数类型来获取特定的Method对象。如果不确定方法参数类型,可能需要遍历getMethods()
或getDeclaredMethods()
返回的所有Method对象,根据方法名和参数类型进行筛选。
使用Method进行动态方法调用的实战案例
假设有一个Calculator
类,包含两个重载的add
方法:
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
}
动态调用这两个方法的示例代码如下:
public class MethodDemo {
public static void main(String[] args) throws Exception {
Calculator calculator = new Calculator();
// 调用int add(int, int)
Method addMethodInt = Calculator.class.getMethod("add", int.class, int.class);
System.out.println(addMethodInt.invoke(calculator, 3, 5)); // 输出:8
// 调用double add(double, double)
Method addMethodDouble = Calculator.class.getMethod("add", double.class, double.class);
System.out.println(addMethodDouble.invoke(calculator, 3.5, 5.5)); // 输出:9.0
}
}
二、Field对象操作
Field对象的定义与获取
在Java反射API中,Field
对象代表类或接口中声明的一个字段(成员变量)。它包含了关于字段的各种元数据,如名称、类型、访问修饰符、注解等,并提供了访问和修改字段值的方法。
获取Field对象主要有以下两种方式:
通过Class对象的getFields()
方法:此方法返回一个包含当前类及其所有父类中所有公有字段(包括继承自超类的公有字段)的Field
数组。这些字段无需被public
修饰符标记,但必须对调用者可见。
Class<?> clazz = MyClass.class;
Field[] publicFields = clazz.getFields();
通过Class对象的getDeclaredFields()
方法:此方法返回一个包含当前类所有声明的字段(不论访问修饰符)的Field
数组,包括私有(private
)、受保护(protected
)和包访问权限(默认无修饰符)的字段,但不包括从超类继承的字段。
Field[] declaredFields = clazz.getDeclaredFields();
Field对象的重要方法与应用
访问/修改字段值:
get(Object obj)
:获取给定对象obj
上对应Field
所表示字段的值。需要传入一个实例对象,因为字段是对象的属性。
Object fieldValue = field.get(instance);
set(Object obj, Object value)
:设置给定对象obj
上对应Field
所表示字段的值为value
。
field.set(instance, newValue);
设置访问权限:
setAccessible(boolean accessible)
:允许或禁止访问私有、受保护的字段。当accessible
设置为true
时,即使字段原本是私有的,也可以通过反射进行访问或修改。这对于实现某些高级的元编程或框架功能非常有用,但应谨慎使用,以免破坏封装性和安全性。
field.setAccessible(true); // 允许访问私有字段
获取字段类型、修饰符、注解等信息:
getType()
:返回字段的Class
对象,表示该字段的类型。
Class<?> fieldType = field.getType();
getModifiers()
:返回字段的访问修饰符位掩码,可以使用Modifier
类的静态方法判断具体的修饰符(如public
、private
、static
、final
等)。
int modifiers = field.getModifiers();
boolean isPublic = Modifier.isPublic(modifiers);
getAnnotations()
:返回该字段上所有注解组成的数组。
Annotation[] annotations = field.getAnnotations();
getAnnotation(Class<T> annotationClass)
:返回该字段上指定类型的注解,如果不存在则返回null
。
MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
使用Field实现动态字段访问与修改的示例
以下是一个使用Field
对象动态访问和修改对象字段值的完整示例:
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class FieldExample {
public static void main(String[] args) throws Exception {
MyClass instance = new MyClass();
// 获取类的Class对象
Class<MyClass> clazz = MyClass.class;
// 获取所有声明的字段
Field[] fields = clazz.getDeclaredFields();
// 遍历字段并打印相关信息
for (Field field : fields) {
System.out.println("Field Name: " + field.getName());
System.out.println("Field Type: " + field.getType().getName());
System.out.println("Modifiers: " + Modifier.toString(field.getModifiers()));
// 设置访问权限,以便访问私有字段
field.setAccessible(true);
// 获取字段值
Object fieldValue = field.get(instance);
System.out.println("Field Value: " + fieldValue);
// 修改字段值(假设字段为String类型)
String newValue = "New Value";
field.set(instance, newValue);
// 再次获取修改后的值
fieldValue = field.get(instance);
System.out.println("Updated Field Value: " + fieldValue);
System.out.println("------------------------");
}
}
static class MyClass {
private String myPrivateField = "Original Value";
protected int myProtectedField = 123;
public boolean myPublicField = true;
}
}
这段代码首先获取MyClass
的Class
对象,然后通过getDeclaredFields()
方法获取所有声明的字段。接着遍历这些字段,设置它们为可访问,获取并打印字段值,修改字段值,再次获取并打印修改后的值。此示例展示了如何使用Field
对象进行动态的字段访问与修改。