概述
每个方法都由修饰符、返回值、参数、注解和抛出的异常组成。而java.lang.reflect.Method类提供了获取上述内容的API。
需要注意的是,反射一个类的方法时不会考虑父类的方法,只会反射当前类的方法。继承的方法也无法被反射。
获取Method
获取Method类对象的方法如下,需要通过Class类对象来调用下面的方法:
成员方法 | 说明 |
---|---|
Method getMethod(String name, Class<?>... parameterTypes) |
根据方法名称和相关参数,来定位需要查找的Method对象并返回,包括由类或接口声明的方法以及从超类和超接口继承的方法。但注意,只能获取由public修饰的方法。 |
Method[] getMethods() |
返回一个包含Method对象的数组,这些对象反映了此Class对象表示的类或接口的所有公共方法,包括由类或接口声明的方法以及从超类和超接口继承的方法。但注意,只能获取由public修饰的方法。 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) |
根据方法名称和相关参数,来定位需要查找的Method对象并返回,可以获取那些public、private、protected等修饰的方法。但不能获取超类、超接口中的任何方法。 |
Method[] getDeclaredMethods() |
返回一个包含Method对象的数组,该对象反映了此Class对象表示的类或接口的所有声明方法,包括公共(public)、受保护(protected)、默认(包)访问和私有(private)方法,但不包括继承的方法。但不能获取超类、超接口中的任何方法。 |
Method getEnclosingMethod() |
如果此Class对象表示方法内的本地类或匿名类,则返回一个Method对象,表示底层类的直接封闭方法。 否则返回null 。 |
上述方法的实例如下:
public class Test {
public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Son son = new Son();
Class<? extends Son> aClass = son.getClass();
// 根据方法名称和相关参数,来定位需要查找的Method对象并返回,包括由类或接口声明的方法以及从超类和超接口继承的方法。
Method method = aClass.getMethod("print", String.class);// 获取本类中的方法
Method printSon = aClass.getMethod("printSon");// 获取父类中的方法
Method reprint = aClass.getMethod("reprint");// 获取接口中的方法
// 返回一个包含Method对象的数组,这些对象反映了此Class对象表示的类或接口的所有公共方法,包括由类或接口声明的方法以及从超类和超接口继承的方法。
Method[] methods = aClass.getMethods();// 获取本类、超类、超接口中的所有方法
for (Method m : methods) {
System.out.println(m.getName());
}
System.out.println("====================================================");
// 根据方法名称和相关参数,来定位需要查找的Method对象并返回,可以获取那些privateer、protected等修饰的方法。
Method privatePrint = aClass.getDeclaredMethod("privatePrint", String.class);
Method printSon2 = aClass.getDeclaredMethod("printSon");
// 返回一个包含Method对象的数组,该对象反映了此Class对象表示的类或接口的所有声明方法,包括公共、受保护、默认(包)访问和私有方法,但不包括继承的方法。但不能获取超类、超接口中的任何方法。
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName());
}
System.out.println("====================================================");
// 如果此Class对象表示方法内的本地类或匿名类,则返回一个Method对象,表示底层类的直接封闭方法。 否则返回null 。
Method enclosingMethod = son.getRunnable().getClass().getEnclosingMethod();// 匿名内部类
Method enclosingMethod2 = son.innerClassMethod().getClass().getEnclosingMethod();
}
}
interface MyInterface {
// 接口中public修饰的方法
public void reprint();
// 接口中的默认方法
default void defaultMethod() {
System.out.println("ddd");
}
}
class Father implements MyInterface {
// 父类中的无参无返回值的public方法
public void print() {
System.out.println("Hello World!");
}
// 父类中的带参带返回值的public方法
public boolean print(String msg) {
if (msg == null) {
return false;
}
System.out.println(msg);
return true;
}
// 实现接口中的方法
@Override
public void reprint() {
System.out.println("reprint...");
}
// 父类中被private修饰的方法
private void hello() {
System.out.println("私有方法");
}
}
class Son extends Father {
// 子类中public修饰的无参无返回值方法
public void printSon() {
System.out.println("Son...");
}
// 子类中protected修饰的带参无返回值方法
protected void privatePrint(String msg) {
System.out.println("私生子..." + msg);
}
// 子类中方法内有本地类,并且将本地类对象返回的方法
public Object innerClassMethod() {
class InnerClass {
}
return new InnerClass();
}
// 子类中使用了匿名内部类的方法
public Runnable getRunnable() {
return new Runnable() {
@Override
public void run() {
System.out.println("run...");
}
};
}
}
/*打印结果:
printSon
innerClassMethod
getRunnable
reprint
print
print
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
defaultMethod
====================================================
printSon
privatePrint
innerClassMethod
getRunnable
====================================================
*/
常用方法
我们知道每个方法都由修饰符、返回值、参数、注解和抛出的异常组成。所以下面的方法是对这些的获取。
获取修饰符
方法可以被以下修饰符修饰:
- 访问权限控制符:public, protected, private
- 静态修饰符:static
- 不允许修改的:final
- 抽象方法:abstract
- 同步锁:synchronized
- 本地方法:native
- 严格的浮点型强度:strictfp
- 注解
成员方法 | 说明 |
---|---|
int getModifiers() |
返回该Method对象所表示方法的修饰符。但返回的是一个整数,所以需要通过Modifier.toString()方法转换成字符串。 |
该方法的实例如下:
public class Test {
public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Son son = new Son();
Class<? extends Son> aClass = son.getClass();
Method[] methods = aClass.getMethods();
for (Method method : methods) {
// 获取方法的修饰符,但返回的是一个整数,所以需要通过Modifier.toString()方法转换成字符串
int modifiers = method.getModifiers();
System.out.println("方法名:" + method.getName() + ", 修饰符:" + Modifier.toString(modifiers));
}
}
}
interface MyInterface {
// 接口中public修饰的方法
public abstract void reprint();
// 接口中的默认方法
default void defaultMethod() {
System.out.println("ddd");
}
}
class Father implements MyInterface {
// 父类中的无参无返回值的public方法
public void print() {
System.out.println("Hello World!");
}
// 父类中的带参带返回值的public方法
public boolean print(String msg) {
if (msg == null) {
return false;
}
System.out.println(msg);
return true;
}
// 实现接口中的方法
@Override
public void reprint() {
System.out.println("reprint...");
}
// 父类中被private修饰的方法
private void hello() {
System.out.println("私有方法");
}
}
class Son extends Father {
// 子类中public修饰的无参无返回值方法
public void printSon() {
System.out.println("Son...");
}
// 子类中protected修饰的带参无返回值方法
protected void privatePrint(String msg) {
System.out.println("私生子..." + msg);
}
// 子类中方法内有本地类,并且将本地类对象返回的方法
public Object innerClassMethod() {
class InnerClass {
}
return new InnerClass();
}
// 子类中使用了匿名内部类的方法
public Runnable getRunnable() {
return new Runnable() {
@Override
public void run() {
System.out.println("run...");
}
};
}
public final static synchronized native void test();
}
/*打印结果:
方法名:test, 修饰符:public static final synchronized native
方法名:printSon, 修饰符:public
方法名:innerClassMethod, 修饰符:public
方法名:getRunnable, 修饰符:public
方法名:print, 修饰符:public
方法名:print, 修饰符:public
方法名:reprint, 修饰符:public
方法名:wait, 修饰符:public final
方法名:wait, 修饰符:public final
方法名:wait, 修饰符:public final native
方法名:equals, 修饰符:public
方法名:toString, 修饰符:public
方法名:hashCode, 修饰符:public native
方法名:getClass, 修饰符:public final native
方法名:notify, 修饰符:public final native
方法名:notifyAll, 修饰符:public final native
方法名:defaultMethod, 修饰符:public
*/
获取返回值类型
可以获取返回值类型的两个方法如下:
成员方法 | 说明 |
---|---|
Class<?> getReturnType() |
返回一个Class对象,该对象表示此Method对象表示的方法的正式返回类型。 |
Type getGenericReturnType() |
返回一个Type对象,该对象表示此Method对象表示的方法的正式返回类型。如果返回类型是参数化类型,则返回的Type对象必须准确反映源代码中使用的实际类型参数。注:如果返回值类型不是泛型,那么两个方法的返回值是一致的;如果是泛型,getGenericReturnType()方法会返回泛型的类型。 |
实例如下:
public class Test {
public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Son son = new Son();
Class<? extends Son> aClass = son.getClass();
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
// 获取返回值类型
// getReturnType(),返回一个Class对象,该对象表示此Method对象表示的方法的正式返回类型。
// getGenericReturnType(),返回一个Type对象,该对象表示此Method对象表示的方法的正式返回类型。如果返回类型是参数化类型,则返回的Type对象必须准确反映源代码中使用的实际类型参数。
// 注:如果不是泛型,那么两个方法的返回值是一致的;如果是泛型,getGenericReturnType()方法会返回泛型的类型
Class<?> returnType = method.getReturnType();
Type genericReturnType = method.getGenericReturnType();
System.out.println(returnType + ", " + genericReturnType);
}
}
}
class Son {
// 基本数据类型的返回值
public int getInt() {
return 1;
}
// 包装类型的返回值
public Boolean getBoolean() {
return Boolean.TRUE;
}
// 引用数据类型的返回值
public String getString() {
return "xxx";
}
// 引用数据类型的返回值
public Test getTest() {
return new Test();
}
// 泛型数据类型的返回值
public List<String> getList() {
return new ArrayList<>();
}
// 泛型数据类型的返回值
public Map<String, Object> getMap() {
return new HashMap<>();
}
}
/*打印结果:
class java.lang.Boolean, class java.lang.Boolean
int, int
interface java.util.Map, java.util.Map<java.lang.String, java.lang.Object>
class java.lang.String, class java.lang.String
interface java.util.List, java.util.List<java.lang.String>
class com.demo.bean.demo.Test, class com.demo.bean.demo.Test
*/
获取参数类型
获取方法参数相关的方法如下:
成员方法 | 说明 |
---|---|
int getParameterCount() |
获取该Method对象所表示方法的参数数量。 |
Parameter[] getParameters() |
返回一个Parameter 对象数组,表示该Method对象所表示方法的所有参数。 |
Class<?>[] getParameterTypes() |
获取该Method对象所表示方法的所有参数类型的数组。 |
Type[] getGenericParameterTypes() |
获取该Method对象所表示方法的所有参数类型的数组,一般情况下,同getParameterTypes() 方法的返回值一样,如果存在泛型,则该方法会返回泛型的类型。 |
对应的实例如下:
public class Test {
public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Son son = new Son();
Class<? extends Son> aClass = son.getClass();
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
// 获取该方法的参数数量
int parameterCount = method.getParameterCount();
// 获取该方法的参数数组
Parameter[] parameters = method.getParameters();
// 获取参数类型数组,getParameterTypes()和getGenericParameterTypes()方法都可以获取,一般情况下返回值类型一样,只有在泛型的情况有些不同
Class<?>[] parameterTypes = method.getParameterTypes();
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
System.out.print("方法名:" + method.getName() + ", 参数类型:" + parameterTypes[i].getTypeName() + ", " + genericParameterTypes[i].getTypeName() + "\t");
}
System.out.println();
}
}
}
class Son {
public void m1(int i) {
}
public void m2(Boolean bool) {
}
public void m3(String str, int i) {
}
public void m4(List<String> list) {
}
public void m5(Integer... nums) {
}
}
/*打印结果:
方法名:m1, 参数类型:int, int
方法名:m3, 参数类型:java.lang.String, java.lang.String 方法名:m3, 参数类型:int, int
方法名:m4, 参数类型:java.util.List, java.util.List<java.lang.String>
方法名:m2, 参数类型:java.lang.Boolean, java.lang.Boolean
方法名:m5, 参数类型:java.lang.Integer[], java.lang.Integer[]
*/
获取抛出异常类型
获取抛出异常类型的方法如下:
成员方法 | 说明 |
---|---|
Class<?>[] getExceptionTypes() |
返回该Method对象所表示方法通过throws子句抛出的异常类型数组,是Class类型的。 |
Type[] getGenericExceptionTypes() |
返回该Method对象所表示方法通过throws子句抛出的异常类型数组,是Type类型的。如果没有抛出任何异常,则返回一个长度为0的数组。 |
实例如下:
public class Test {
public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Son son = new Son();
Class<? extends Son> aClass = son.getClass();
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
// 获取异常类型
// getExceptionTypes(),返回该Method对象所表示方法通过throws子句抛出的异常类型数组,是Class类型的
// getGenericExceptionTypes(),返回该Method对象所表示方法通过throws子句抛出的异常类型数组,是Type类型的
Class<?>[] exceptionTypes = method.getExceptionTypes();
Type[] genericExceptionTypes = method.getGenericExceptionTypes();
for (int i = 0; i < exceptionTypes.length; i++) {
System.out.println("方法名:" + method.getName() + "; 异常类型:" + exceptionTypes[i] + ", " + genericExceptionTypes[i]);
}
}
}
}
class Son {
public void m1(int i) throws NullPointerException {
}
public void m2(Boolean bool) throws IllegalArgumentException {
}
public void m3(String str, int i) throws DateTimeParseException {
}
public void m4(List<String> list) throws IOException {
}
public void m5(Integer... nums) throws Exception {
}
}
/*打印结果:
方法名:m3; 异常类型:class java.time.format.DateTimeParseException, class java.time.format.DateTimeParseException
方法名:m2; 异常类型:class java.lang.IllegalArgumentException, class java.lang.IllegalArgumentException
方法名:m1; 异常类型:class java.lang.NullPointerException, class java.lang.NullPointerException
方法名:m4; 异常类型:class java.io.IOException, class java.io.IOException
方法名:m5; 异常类型:class java.lang.Exception, class java.lang.Exception
*/
获取方法上的注解
方法如下:
成员方法 | 说明 |
---|---|
Annotation[] getAnnotations() |
获取该Method对象所表示方法上的所有注解。 |
<T extends Annotation> T getAnnotation(Class<T> annotationClass) |
获取该Method对象所表示方法上指定注解类,如果该方法上存在该注解则返回该注解类,否则返回null。 |
Annotation[] getDeclaredAnnotations() |
返回直接存在该Method对象所表示方法上的所有注解,但会忽略掉继承的注解。如果该方法上没有直接存在的注解,则返回值是一个长度为0的数组。 |
<T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) |
返回直接存在该Method对象所表示方法上的指定类注解,但会忽略掉继承的注解。如果该方法上没有直接存在的注解,则返回值是一个长度为0的数组。 |
<T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) |
如果该方法对象存在指定类型的注解,则返回该注解数组,否则返回 null。只有类级别的注解会被继承得到,对于其他对象而言,getAnnotationsByType() 方法与 getDeclaredAnnotationsByType() 方法作用相同。getAnnotationsByType() 方法与 getAnnotation() 方法的区别在于:getAnnotationsByType() 方法会检查修饰该方法对象的注解是否为可重复类型注解,如果是则会返回修饰该方法对象的一个或多个注解。@Repeatable 用于声明注解为可重复类型注解。当声明为可重复类型注解后,如果方法注解仍为一个,则 getAnnotation() 方法会正常返回,如果方法注解为多个,则 getAnnotation() 方法会返回 null。 |
<T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) |
如果该方法对象存在指定类型的注解,则返回该注解数组,否则返回 null。只有类级别的注解会被继承得到,对于其他对象而言,getAnnotationsByType() 方法与 getDeclaredAnnotationsByType() 方法作用相同。 |
实例如下:
public class Test {
public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Son son = new Son();
Class<? extends Son> aClass = son.getClass();
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
// 获取注解
Annotation[] annotations = method.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
System.out.print("方法名:" + method.getName() + "; 注解类型:" + annotation);
}
System.out.println();
// 获取某个注解类
// AnnotationMethod annotation = method.getAnnotation(AnnotationMethod.class);
// System.out.println(annotation);
}
}
}
class Son {
@Deprecated
public void m1() {
}
@AnnotationMethod()
public void m2() {
}
@AnnotationMethod(name = "xxx")
public void m3() {
}
@AnnotationMethod(name = "xxx", nums = {1, 2, 3, 4})
public void m4() {
}
@AnnotationMethod(nums = {1, 2, 3, 4})
private void m5() {
}
@C
public void m6() {
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {METHOD, TYPE})
@interface A {
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {METHOD, TYPE})
@interface B {
}
@Inherited
@A
@B
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {METHOD, TYPE})
@interface C {
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {METHOD})
@Inherited
@interface AnnotationMethod {
String name() default "";
int[] nums() default {};
}
/*打印结果:
方法名:m1; 注解类型:@java.lang.Deprecated()
方法名:m2; 注解类型:@com.demo.bean.demo.AnnotationMethod(name=, nums=[])
方法名:m3; 注解类型:@com.demo.bean.demo.AnnotationMethod(name=xxx, nums=[])
方法名:m4; 注解类型:@com.demo.bean.demo.AnnotationMethod(name=xxx, nums=[1, 2, 3, 4])
方法名:m6; 注解类型:@com.demo.bean.demo.C()
方法名:m5; 注解类型:@com.demo.bean.demo.AnnotationMethod(name=, nums=[1, 2, 3, 4])
*/
其他方法
成员方法 | 说明 |
---|---|
String getName() |
返回由此Method对象表示的方法的名称,作为String 。 |
Object invoke(Object obj, Object... args) |
执行方法,可以传递参数,返回值就是执行该方法后的返回值。 |
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) |
如果该方法对象上有指定类型的注解,则返回 true,否则为 false。 |
boolean isVarArgs() |
如果该方法对象的参数中存在 可变参数(例如String...args ),则返回 true,否则为 false。 |
Object getDefaultValue() |
返回该注解方法对象表示的成员默认值。如果成员属于基本数据类型,则返回对应的包装类实例。如果没有默认值或者该方法实例不表示注解方法,则返回 null。 |
String toString() |
返回该方法对象的字符串表示形式 (擦除泛型)。 |
String toGenericString() |
返回该方法对象的字符串表示形式 (保留泛型)。 |
boolean isAccessible() |
获取该方法对象Method的可访问标志。 |
void setAccessible(boolean flag) |
设置该方法对象的可访问标志。在其他类里调用该方法对象时,如果该方法为私有方法,需要设置访问标志为 true,否则会报异常。 |
boolean isDefault() |
判断该方法对象是否为默认方法,如果是则返回 true,否则为 false。默认方法即是使用default关键字修饰的方法。 |
boolean isSynthetic() |
判断该方法对象是否为合成方法,如果是则返回 true,否则为 false。比如在内部类 中,有一个私有属性,而我们在外部类中,直接引用了这个属性,那么编译器会生成一个合成方法,用于绕开 private 私有属性的限制。 |
boolean isBridge() |
判断该方法对象是否桥接方法,如果是则返回 true,否则为 false。桥接方法是 JDK1.5 引入泛型后,为了使 Java 的泛型方法生成的字节码和 1.5 版本前的字节码相兼容,由编译器自动生成的方法。 |
实例:
public class Test {
public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Son son = new Son();
Class<? extends Son> aClass = son.getClass();
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
// 获取方法名
System.out.println("方法名:" + method.getName());
if (method.getParameterCount() == 0) {
// 调用执行方法
method.invoke(son);
} else if (method.getParameterCount() == 1) {
method.invoke(son, "我是传入的参数");
} else if (method.getParameterCount() == 2) {
Object returnValue = method.invoke(son, "我是第一个参数", "我是第二个参数");
System.out.println(returnValue);
}
System.out.println("================================");
}
}
}
class Son {
public void hello() {
System.out.println("Hello World!");
}
public void hello(String msg) {
System.out.println(msg);
}
public String hello(String str1, String str2) {
return str1 + "," + str2;
}
}
/*打印结果:
方法名:hello
我是第一个参数,我是第二个参数
================================
方法名:hello
Hello World!
================================
方法名:hello
我是传入的参数
================================
*/