Java 类之 java.lang.reflect.Method
文章目录
- Java 类之 java.lang.reflect.Method
- 一、概述
- 1、java.lang.Class 类获取方法的方法
- 获取全部公有方法(含继承的,不含私有的)
- 获取本类的所有方法(不含继承的,含私有的)
- 代码示例
- 2、java.lang.reflect.Method 类简介
- 3、类定义信息
- 二、基本功能
- 1、基本功能
- 2、代码示例
- 三、扩展
- 1、关于注解的方法
- 2、`getAnnotations()` 和 `getDeclaredAnnotations()`的区别
- 区别
- 代码示例
- 3、invoke 方法
- 简介
- 方法签名
- 参数说明
- 异常
- 代码示例
- 4、是否支持修改方法
- 5、其它注意点
关联文章:《Java反射详解》
一、概述
1、java.lang.Class 类获取方法的方法
获取全部公有方法(含继承的,不含私有的)
getMethod(String name, Class<?>... parameterTypes)
:
- 获取指定名称和参数类型的公有方法。
- 如果方法不存在,则抛出
NoSuchMethodException
异常。
getMethods()
:
- 获取该类及其父类中所有公有方法的数组。
- 返回一个
Method
对象数组。
获取本类的所有方法(不含继承的,含私有的)
getDeclaredMethod(String name, Class<?>... parameterTypes)
:
- 获取指定名称和参数类型的任意访问权限的方法,包括私有方法。
- 如果方法不存在,则抛出
NoSuchMethodException
异常。
getDeclaredMethods()
:
- 获取该类中所有声明的方法,包括私有方法。
- 返回一个
Method
对象数组。
代码示例
// 获取公有方法(含继承的,不含私有的)
Method publicMethod = MyClass.class.getMethod("publicMethodName", String.class);
// 获取所有公有方法(含继承的,不含私有的)
Method[] publicMethods = MyClass.class.getMethods();
// 获取本类的私有方法(不含继承的,含私有的)
Method privateMethod = MyClass.class.getDeclaredMethod("privateMethodName", String.class);
// 获取本类的所有方法(不含继承的,含私有的)
Method[] allMethods = MyClass.class.getDeclaredMethods();
2、java.lang.reflect.Method 类简介
java.lang.reflect.Method
类是 Java 反射机制中的一部分,用于表示类的方法。反射是一种在运行时检查或修改类的行为的能力。Method
类提供了对类的方法的信息的访问和操作。
3、类定义信息
public final class Method extends Executable
二、基本功能
1、基本功能
- 获取方法信息:
Method
类允许你获取关于方法的各种信息,如方法名、返回类型、参数类型等。 - 调用方法: 你可以使用
invoke
方法动态地调用类的方法,即使在编译时并不知道方法的具体存在。 - 获取修饰符: 通过
getModifiers
方法,你可以获取方法的修饰符,如public
、private
、static
等。 - 获取注解: 使用
getAnnotation
方法,你可以获取方法上指定类型的注解。
2、代码示例
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class MethodExample {
public static void main(String[] args) throws Exception {
// 获取 String 类的所有方法
Method[] methods = String.class.getMethods();
// 遍历方法数组
for (Method method : methods) {
// 获取方法名
String methodName = method.getName();
System.out.println("Method Name: " + methodName);
// 获取返回类型
Class<?> returnType = method.getReturnType();
System.out.println("Return Type: " + returnType.getSimpleName());
// 获取参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
System.out.print("Parameter Types: ");
for (Class<?> paramType : parameterTypes) {
System.out.print(paramType.getSimpleName() + " ");
}
System.out.println();
// 获取修饰符
int modifiers = method.getModifiers();
System.out.println("Modifiers: " + Modifier.toString(modifiers));
// 获取注解
if (method.isAnnotationPresent(Deprecated.class)) {
System.out.println("Method is Deprecated!");
}
System.out.println("---------------------------------------------");
}
// 调用 String 类的 length 方法
Method lengthMethod = String.class.getMethod("length");
String str = "Hello, World!";
int length = (int) lengthMethod.invoke(str);
System.out.println("Length of the string: " + length);
}
}
三、扩展
1、关于注解的方法
- getAnnotation(Class annotationClass):
- 用途:获取指定类型的注解。
- 参数:
annotationClass
- 要获取的注解的 Class 对象。 - 返回值:指定类型的注解对象,如果该方法没有找到注解,则返回 null。
- getAnnotations():
- 用途:获取该方法上的所有注解。
- 返回值:一个包含此元素上存在的所有注解的数组。
- getDeclaredAnnotation(Class annotationClass):
- 用途:获取直接存在于此元素上的、指定类型的注解。
- 参数:
annotationClass
- 要获取的注解的 Class 对象。 - 返回值:指定类型的注解对象,如果该方法没有找到注解,则返回 null。
- getDeclaredAnnotations():
- 用途:获取直接存在于此元素上的所有注解。
- 返回值:一个包含此元素上存在的所有注解的数组。
- isAnnotationPresent(Class<? extends Annotation> annotationClass):
- 用途:判断指定类型的注解是否存在于该元素上。
- 参数:
annotationClass
- 要检查的注解的 Class 对象。 - 返回值:如果指定类型的注解存在于此元素上,则返回 true;否则返回 false。
2、getAnnotations()
和 getDeclaredAnnotations()
的区别
区别
getAnnotations()
和 getDeclaredAnnotations()
是 java.lang.reflect.Method
类中用于获取方法上注解的两个方法,它们之间存在一些区别:
- 范围:
-
getAnnotations()
: 返回此元素上存在的所有注解,包括从父类、接口继承而来的注解。 -
getDeclaredAnnotations()
: 返回直接存在于此元素上的所有注解,不包括继承而来的注解。
- 继承:
-
getAnnotations()
: 包括继承而来的注解,即如果该方法在父类或接口中有注解,也会被返回。 -
getDeclaredAnnotations()
: 只返回直接在当前方法上声明的注解,不包括继承而来的注解。
- 可见性:
-
getAnnotations()
: 返回的注解包括所有可见的注解,无论其访问级别是public
、protected
、default
还是private
。 -
getDeclaredAnnotations()
: 只返回当前方法上直接声明的注解,与其可见性无关。
代码示例
仅作参考!
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class AnnotationExample {
@CustomAnnotation
public void annotatedMethod() {
// Method with annotation
}
public static void main(String[] args) throws NoSuchMethodException {
Class<?> clazz = AnnotationExample.class;
Method method = clazz.getMethod("annotatedMethod");
// getAnnotations() - 包括继承而来的注解
Annotation[] annotations = method.getAnnotations();
System.out.println("getAnnotations() - Total Annotations: " + annotations.length);
// getDeclaredAnnotations() - 只返回直接声明的注解
Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
System.out.println("getDeclaredAnnotations() - Total Annotations: " + declaredAnnotations.length);
}
}
// Custom Annotation
@interface CustomAnnotation {
}
3、invoke 方法
简介
invoke
方法是 java.lang.reflect.Method
类中的一个重要方法,用于在运行时动态地调用方法。该方法允许你通过反射机制调用指定对象的特定方法,即使在编译时你可能不知道这个方法的具体存在。
方法签名
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
参数说明
-
obj
:要调用方法的对象。如果方法是静态的,则可以将obj
参数设置为null
。 -
args
:要传递给方法的参数数组。
异常
-
IllegalAccessException
:如果底层方法是私有的、受保护的或者包访问级别,并且无法访问。 -
IllegalArgumentException
:如果提供的参数不匹配方法的参数。 -
InvocationTargetException
:如果底层方法抛出异常,则包装在InvocationTargetException
中。
代码示例
import java.lang.reflect.Method;
public class InvokeExample {
public static void main(String[] args) throws Exception {
// 获取 String 类的 length 方法
Method lengthMethod = String.class.getMethod("length");
// 创建一个字符串对象
String str = "Hello, World!";
// 调用 length 方法
int length = (int) lengthMethod.invoke(str);
System.out.println("Length of the string: " + length);
}
}
4、是否支持修改方法
在 Java 中,通过反射机制可以在运行时获取和调用方法,但并不直接支持对方法的修改。反射主要用于获取关于类和方法的信息,以及在运行时动态调用方法,而不是用于修改类的结构。
方法的修改通常是在编译时完成的,而不是在运行时。在 Java 中,类一旦加载就被认为是不可修改的(除非使用特殊的技术,如字节码增强库,但这并不是标准的 Java 功能)。
如果你想要修改类的行为,你可能需要考虑其他方式,如使用代理模式、AOP(面向切面编程)或字节码操作库,例如 ASM 或 Byte Buddy。这些方法允许你在运行时对类的行为进行一些定制,但也需要小心使用,以避免不稳定和难以维护的代码。
总体而言,Java 的设计哲学是在编译时进行尽可能多的检查和优化,以提高代码的性能和可靠性。因此,动态修改类的结构并不是 Java 语言的主要特性,而是通过其他手段来实现。
5、其它注意点
- 异常处理: 使用
invoke
方法时,需要注意处理可能抛出的异常,包括IllegalAccessException
、IllegalArgumentException
和InvocationTargetException
。这些异常可能在调用方法时发生,因此需要进行适当的异常处理。
try {
// 调用方法的代码
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// 处理异常的代码
}
- 可访问性: 如果调用的方法是私有的、受保护的或者包访问级别的,需要通过
setAccessible(true)
方法设置方法为可访问,否则会抛出IllegalAccessException
异常。
method.setAccessible(true);
注意:在访问私有方法时,这可能会涉及到安全性和代码规范的问题,应该慎重使用。
- 方法参数和返回值: 在调用方法时,需要确保传递的参数类型和个数与方法的参数匹配,并且要注意类型转换。同样,需要根据方法的返回类型进行适当的类型转换。
// 获取方法的参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
// 检查参数是否匹配,然后调用方法
if (parameterTypes.length == args.length) {
method.invoke(obj, args);
}
- 性能影响: 反射操作相对于直接调用方法会有一些性能开销,因此在高性能要求的情况下,应谨慎使用反射。如果可能,可以考虑使用直接的方法调用来提高性能。
- 泛型处理: 如果方法使用了泛型,需要注意处理泛型类型擦除的情况。在获取方法的参数类型或返回类型时,可能需要使用
getGenericParameterTypes
和getGenericReturnType
来获取泛型信息。
java.lang.reflect.Type[] genericParameterTypes = method.getGenericParameterTypes();
java.lang.reflect.Type genericReturnType = method.getGenericReturnType();