Method类的使用

概述

每个方法都由修饰符返回值参数注解抛出的异常组成。而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
    我是传入的参数
    ================================
 */

参考链接:

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值