首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >反射基础之Method

反射基础之Method

作者头像
代码拾遗
发布2018-07-24 15:50:09
1.6K0
发布2018-07-24 15:50:09
举报
文章被收录于专栏:代码拾遗代码拾遗

获取方法类型信息

一个方法声明包括:方法名,描述符,参数,返回类型和异常。可以通过java.lang.reflect.Method类获取这些信息。 下面的例子说明了如何获取一个类中所有的方法,根据名字获取方法的返回类型,参数,异常等。

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import static java.lang.System.out;

public class MethodSpy {
    private static final String  fmt = "%24s: %s%n";

    // for the morbidly curious
    <E extends RuntimeException> void genericThrow() throws E {}

    public static void main(String... args) {
    try {
        Class<?> c = Class.forName(args[0]);
        Method[] allMethods = c.getDeclaredMethods();
        for (Method m : allMethods) {
        if (!m.getName().equals(args[1])) {
            continue;
        }
        out.format("%s%n", m.toGenericString());

        out.format(fmt, "ReturnType", m.getReturnType());
        out.format(fmt, "GenericReturnType", m.getGenericReturnType());

        Class<?>[] pType  = m.getParameterTypes();
        Type[] gpType = m.getGenericParameterTypes();
        for (int i = 0; i < pType.length; i++) {
            out.format(fmt,"ParameterType", pType[i]);
            out.format(fmt,"GenericParameterType", gpType[i]);
        }

        Class<?>[] xType  = m.getExceptionTypes();
        Type[] gxType = m.getGenericExceptionTypes();
        for (int i = 0; i < xType.length; i++) {
            out.format(fmt,"ExceptionType", xType[i]);
            out.format(fmt,"GenericExceptionType", gxType[i]);
        }
        }

        // production code should handle these exceptions more gracefully
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    }
    }
}

运行:

$ java MethodSpy java.lang.Class getConstructor
public java.lang.reflect.Constructor<T> java.lang.Class.getConstructor
  (java.lang.Class<?>[]) throws java.lang.NoSuchMethodException,
  java.lang.SecurityException
              ReturnType: class java.lang.reflect.Constructor
       GenericReturnType: java.lang.reflect.Constructor<T>
           ParameterType: class [Ljava.lang.Class;
    GenericParameterType: java.lang.Class<?>[]
           ExceptionType: class java.lang.NoSuchMethodException
    GenericExceptionType: class java.lang.NoSuchMethodException
           ExceptionType: class java.lang.SecurityException
    GenericExceptionType: class java.lang.SecurityException]

源码中方法定义public Constructor<T> getConstructor(Class<?>... parameterTypes)。 首先注意,返回类型和参数类型是泛型类型。如果在class文件中提供了Signature Attribute Method.getGenericReturnType() 计算出其泛型类型。如果没有提供则使用Method.getReturnType(),这个并不会带有泛型信息。 其次注意,parameterTypes 是可变参数,类型是java.lang.Class 。可变参数列表被表示为一维数组。可以通过Method.isVarArgs() 来区别是否是可变参数。 如果返回值是泛型运行如下:

$ java MethodSpy java.lang.Class cast
public T java.lang.Class.cast(java.lang.Object)
              ReturnType: class java.lang.Object
       GenericReturnType: T
           ParameterType: class java.lang.Object
    GenericParameterType: class java.lang.Object

对于重载函数则会显示所有的重载函数信息:

$ java MethodSpy java.io.PrintStream format
public java.io.PrintStream java.io.PrintStream.format
  (java.util.Locale,java.lang.String,java.lang.Object[])
              ReturnType: class java.io.PrintStream
       GenericReturnType: class java.io.PrintStream
           ParameterType: class java.util.Locale
    GenericParameterType: class java.util.Locale
           ParameterType: class java.lang.String
    GenericParameterType: class java.lang.String
           ParameterType: class [Ljava.lang.Object;
    GenericParameterType: class [Ljava.lang.Object;
public java.io.PrintStream java.io.PrintStream.format
  (java.lang.String,java.lang.Object[])
              ReturnType: class java.io.PrintStream
       GenericReturnType: class java.io.PrintStream
           ParameterType: class java.lang.String
    GenericParameterType: class java.lang.String
           ParameterType: class [Ljava.lang.Object;
    GenericParameterType: class [Ljava.lang.Object;]]]]
获取方法的参数名

可以通过java.lang.reflect.Executable.getParameters()方法获取方法的参数名,Method和Constructor都继承与java.lang.reflect.Executable,所有都可以使用这个函数。然后class文件默认并不保存方法这些信息。因为很多工具生成和获取class文件的时候都不会希望有大量的参数名字信息。尤其是这些工具处理大的class文件的时候,JVM将会使用更多的内存。另外,参数名,例如:secret或者password,可能会暴露一些安全敏感的信息。 可以在编译的时候使用-parameters 将参数名保存到class文件中。 下面的例子展示了如何获取参数信息:

import java.lang.reflect.*;
import java.util.function.*;
import static java.lang.System.out;

public class MethodParameterSpy {

    private static final String  fmt = "%24s: %s%n";

    // for the morbidly curious
    <E extends RuntimeException> void genericThrow() throws E {}

    public static void printClassConstructors(Class c) {
        Constructor[] allConstructors = c.getConstructors();
        out.format(fmt, "Number of constructors", allConstructors.length);
        for (Constructor currentConstructor : allConstructors) {
            printConstructor(currentConstructor);
        }  
        Constructor[] allDeclConst = c.getDeclaredConstructors();
        out.format(fmt, "Number of declared constructors",
            allDeclConst.length);
        for (Constructor currentDeclConst : allDeclConst) {
            printConstructor(currentDeclConst);
        }          
    }

    public static void printClassMethods(Class c) {
       Method[] allMethods = c.getDeclaredMethods();
        out.format(fmt, "Number of methods", allMethods.length);
        for (Method m : allMethods) {
            printMethod(m);
        }        
    }

    public static void printConstructor(Constructor c) {
        out.format("%s%n", c.toGenericString());
        Parameter[] params = c.getParameters();
        out.format(fmt, "Number of parameters", params.length);
        for (int i = 0; i < params.length; i++) {
            printParameter(params[i]);
        }
    }

    public static void printMethod(Method m) {
        out.format("%s%n", m.toGenericString());
        out.format(fmt, "Return type", m.getReturnType());
        out.format(fmt, "Generic return type", m.getGenericReturnType());

        Parameter[] params = m.getParameters();
        for (int i = 0; i < params.length; i++) {
            printParameter(params[i]);
        }
    }

    public static void printParameter(Parameter p) {
        out.format(fmt, "Parameter class", p.getType());
        out.format(fmt, "Parameter name", p.getName());
        out.format(fmt, "Modifiers", p.getModifiers());
        out.format(fmt, "Is implicit?", p.isImplicit());
        out.format(fmt, "Is name present?", p.isNamePresent());
        out.format(fmt, "Is synthetic?", p.isSynthetic());
    }

    public static void main(String... args) {        

        try {
            printClassConstructors(Class.forName(args[0]));
            printClassMethods(Class.forName(args[0]));
        } catch (ClassNotFoundException x) {
            x.printStackTrace();
        }
    }
}

编译时记得使用-parameter参数,运行 结果如下:

Number of constructors: 1

Constructor #1
public ExampleMethods()

Number of declared constructors: 1

Declared constructor #1
public ExampleMethods()

Number of methods: 4

Method #1
public boolean ExampleMethods.simpleMethod(java.lang.String,int)
             Return type: boolean
     Generic return type: boolean
         Parameter class: class java.lang.String
          Parameter name: stringParam
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false
         Parameter class: int
          Parameter name: intParam
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false

Method #2
public int ExampleMethods.varArgsMethod(java.lang.String...)
             Return type: int
     Generic return type: int
         Parameter class: class [Ljava.lang.String;
          Parameter name: manyStrings
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false

Method #3
public boolean ExampleMethods.methodWithList(java.util.List<java.lang.String>)
             Return type: boolean
     Generic return type: boolean
         Parameter class: interface java.util.List
          Parameter name: listParam
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false

Method #4
public <T> void ExampleMethods.genericMethod(T[],java.util.Collection<T>)
             Return type: void
     Generic return type: void
         Parameter class: class [Ljava.lang.Object;
          Parameter name: a
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false
         Parameter class: interface java.util.Collection
          Parameter name: c
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false

Parameter 类的方法是用:

  • getType(): 返回Class对象,表明参数的类型
  • getName(): 返回参数名子。如果有名字则返回名字,如果没有合成参数名argN N是参数的顺序。

例如如果不是用-parameter 参数:

public boolean ExampleMethods.simpleMethod(java.lang.String,int)
             Return type: boolean
     Generic return type: boolean
         Parameter class: class java.lang.String
          Parameter name: arg0
               Modifiers: 0
            Is implicit?: false
        Is name present?: false
           Is synthetic?: false
         Parameter class: int
          Parameter name: arg1
               Modifiers: 0
            Is implicit?: false
        Is name present?: false
           Is synthetic?: false
  • getModifiers(): 返回代表修饰符的数字。
  • isImplicit(): 如果参数是隐式声明则返回true
  • isNamePresent(): 如果class中有参数名信息返回true。
  • isSynthetic(): 如果参数既没有显示也没有隐式的在源码中声明,返回true。
隐式和合成参数

某些构造函数是隐式声明在源码中的。例如ExampleMethods没有一个显式声明的构造函数则会默认一个隐式的构造函数。如:

Number of declared constructors: 1
public ExampleMethods()

对于内部函数:

public class MethodParameterExamples {
    public class InnerClass { }
}

InnerClass是一个非静态的类,其内部也会有一个隐式的构造函数声明,但是这个隐式构造器会包含一个参数,如下,包含了其外围函数的引用:

public class MethodParameterExamples {
    public class InnerClass {
        final MethodParameterExamples parent;
        InnerClass(final MethodParameterExamples this$0) {
            parent = this$0; 
        }
    }
}

所以运行MethodParameterExample会得到如下结果:

public MethodParameterExamples$InnerClass(MethodParameterExamples)
         Parameter class: class MethodParameterExamples
          Parameter name: this$0
               Modifiers: 32784
            Is implicit?: true
        Is name present?: true
           Is synthetic?: false

如果一个构造器既不是显式声明的也不是隐式声明的难而是有Java编译器生成的则被标记为合成的。例如:

public class MethodParameterExamples {
    enum Colors {
        RED, WHITE;
    }
}

对于enum java编译的时候会补充完其完整信息:

final class Colors extends java.lang.Enum<Colors> {
    public final static Colors RED = new Colors("RED", 0);
    public final static Colors BLUE = new Colors("WHITE", 1);

    private final static values = new Colors[]{ RED, BLUE };

    private Colors(String name, int ordinal) {
        super(name, ordinal);
    }

    public static Colors[] values(){
        return values;
    }

    public static Colors valueOf(String name){
        return (Colors)java.lang.Enum.valueOf(Colors.class, name);
    }
}

这也就是为什么enum不能继承类只能继承接口的原因,因为他已经击沉过了Enum类。

获取并解析方法修饰符

方法的修饰符有:

  • 访问修饰符:pubic,protected,private
  • 静态修饰符:static
  • 不可变修饰符: final
  • 抽象修饰符: abstract
  • 同步修饰符: synchronized
  • 本地方法修饰符: native
  • 严格浮点修饰符: strictfp
  • 注解

下例现实了如何获取修饰符信息:

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import static java.lang.System.out;

public class MethodModifierSpy {

    private static int count;
    private static synchronized void inc() { count++; }
    private static synchronized int cnt() { return count; }

    public static void main(String... args) {
    try {
        Class<?> c = Class.forName(args[0]);
        Method[] allMethods = c.getDeclaredMethods();
        for (Method m : allMethods) {
        if (!m.getName().equals(args[1])) {
            continue;
        }
        out.format("%s%n", m.toGenericString());
        out.format("  Modifiers:  %s%n",
               Modifier.toString(m.getModifiers()));
        out.format("  [ synthetic=%-5b var_args=%-5b bridge=%-5b ]%n",
               m.isSynthetic(), m.isVarArgs(), m.isBridge());
        inc();
        }
        out.format("%d matching overload%s found%n", cnt(),
               (cnt() == 1 ? "" : "s"));

        // production code should handle this exception more gracefully
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    }
    }
}

运行结果如下:

$ java MethodModifierSpy java.lang.Object wait
public final void java.lang.Object.wait() throws java.lang.InterruptedException
  Modifiers:  public final
  [ synthetic=false var_args=false bridge=false ]
public final void java.lang.Object.wait(long,int)
  throws java.lang.InterruptedException
  Modifiers:  public final
  [ synthetic=false var_args=false bridge=false ]
public final native void java.lang.Object.wait(long)
  throws java.lang.InterruptedException
  Modifiers:  public final native
  [ synthetic=false var_args=false bridge=false ]
3 matching overloads found

$ java MethodModifierSpy java.lang.StrictMath toRadians
public static double java.lang.StrictMath.toRadians(double)
  Modifiers:  public static strictfp
  [ synthetic=false var_args=false bridge=false ]
1 matching overload found

$ java MethodModifierSpy MethodModifierSpy inc
private synchronized void MethodModifierSpy.inc()
  Modifiers: private synchronized
  [ synthetic=false var_args=false bridge=false ]
1 matching overload found

$ java MethodModifierSpy java.lang.Class getConstructor
public java.lang.reflect.Constructor<T> java.lang.Class.getConstructor
  (java.lang.Class<T>[]) throws java.lang.NoSuchMethodException,
  java.lang.SecurityException
  Modifiers: public transient
  [ synthetic=false var_args=true bridge=false ]
1 matching overload found

$ java MethodModifierSpy java.lang.String compareTo
public int java.lang.String.compareTo(java.lang.String)
  Modifiers: public
  [ synthetic=false var_args=false bridge=false ]
public int java.lang.String.compareTo(java.lang.Object)
  Modifiers: public volatile
  [ synthetic=true  var_args=false bridge=true  ]
2 matching overloads found
方法调用

可以使用java.lang.reflect.Method.invoke()方法调用反射获取的方法。第一个参数是被调用的对象实例,如果是static函数,第一个参数可以是null,接下来的参数是函数的参数。如果执行发生错误,会被java.lang.reflect.InvocationTargetException异常包装,函数原有异常可以功过InvocationTargetExcetpion.getCause()获取。

查找指定方法并执行:

示例:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Locale;
import static java.lang.System.out;
import static java.lang.System.err;

public class Deet<T> {
    private boolean testDeet(Locale l) {
    // getISO3Language() may throw a MissingResourceException
    out.format("Locale = %s, ISO Language Code = %s%n", l.getDisplayName(), l.getISO3Language());
    return true;
    }

    private int testFoo(Locale l) { return 0; }
    private boolean testBar() { return true; }

    public static void main(String... args) {
    if (args.length != 4) {
        err.format("Usage: java Deet <classname> <langauge> <country> <variant>%n");
        return;
    }

    try {
        Class<?> c = Class.forName(args[0]);
        Object t = c.newInstance();

        Method[] allMethods = c.getDeclaredMethods();
        for (Method m : allMethods) {
        String mname = m.getName();
        if (!mname.startsWith("test")
            || (m.getGenericReturnType() != boolean.class)) {
            continue;
        }
        Type[] pType = m.getGenericParameterTypes();
        if ((pType.length != 1)
            || Locale.class.isAssignableFrom(pType[0].getClass())) {
            continue;
        }

        out.format("invoking %s()%n", mname);
        try {
            m.setAccessible(true);
            Object o = m.invoke(t, new Locale(args[1], args[2], args[3]));
            out.format("%s() returned %b%n", mname, (Boolean) o);

        // Handle any exceptions thrown by method to be invoked.
        } catch (InvocationTargetException x) {
            Throwable cause = x.getCause();
            err.format("invocation of %s failed: %s%n",
                   mname, cause.getMessage());
        }
        }

        // production code should handle these exceptions more gracefully
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    } catch (InstantiationException x) {
        x.printStackTrace();
    } catch (IllegalAccessException x) {
        x.printStackTrace();
    }
    }
}

Deet调用getDelcaredMethods()返回所有的方法。Class.isAssignableFrom() 用来检测参数类型和调用的方法的参数类型是否一致。因为Locale是final类型的,所以可以使用Local.class == pType[0].getClass()来测试,不过Class.isAssignableFrom()更常用。 运行结果:

$ java Deet Deet ja JP JP
invoking testDeet()
Locale = Japanese (Japan,JP), 
ISO Language Code = jpn
testDeet() returned true

$ java Deet Deet xx XX XX
invoking testDeet()
invocation of testDeet failed: 
Couldn't find 3-letter language code for xx

可变参数调用:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class InvokeMain {
    public static void main(String... args) {
    try {
        Class<?> c = Class.forName(args[0]);
        Class[] argTypes = new Class[] { String[].class };
        Method main = c.getDeclaredMethod("main", argTypes);
        String[] mainArgs = Arrays.copyOfRange(args, 1, args.length);
        System.out.format("invoking %s.main()%n", c.getName());
        main.invoke(null, (Object)mainArgs);

        // production code should handle these exceptions more gracefully
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    } catch (NoSuchMethodException x) {
        x.printStackTrace();
    } catch (IllegalAccessException x) {
        x.printStackTrace();
    } catch (InvocationTargetException x) {
        x.printStackTrace();
    }
    }
}

运行结果:

$ java InvokeMain Deet Deet ja JP JP
invoking Deet.main()
invoking testDeet()
Locale = Japanese (Japan,JP), 
ISO Language Code = jpn
testDeet() returned true
问题排查
由于类型擦除导致的 NoSuchMethodException

示例:

import java.lang.reflect.Method;

public class MethodTrouble<T>  {
    public void lookup(T t) {}
    public void find(Integer i) {}

    public static void main(String... args) {
    try {
        String mName = args[0];
        Class cArg = Class.forName(args[1]);
        Class<?> c = (new MethodTrouble<Integer>()).getClass();
        Method m = c.getMethod(mName, cArg);
        System.out.format("Found:%n  %s%n", m.toGenericString());

        // production code should handle these exceptions more gracefully
    } catch (NoSuchMethodException x) {
        x.printStackTrace();
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    }
    }
}

运行结果:

$ java MethodTrouble lookup java.lang.Integer
java.lang.NoSuchMethodException: MethodTrouble.lookup(java.lang.Integer)
        at java.lang.Class.getMethod(Class.java:1605)
        at MethodTrouble.main(MethodTrouble.java:12)

$ java MethodTrouble lookup java.lang.Object
Found:
  public void MethodTrouble.lookup(T)

因为方法声明中有反省类型,编译器会将会使用他的上界替换泛型类型,在这个例子中T的上界是Object。因此编译后无法找到lookup(Integer)的方法。

调用方法是抛出 IllegalAccessException
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class AnotherClass {
    private void m() {}
}

public class MethodTroubleAgain {
    public static void main(String... args) {
    AnotherClass ac = new AnotherClass();
    try {
        Class<?> c = ac.getClass();
        Method m = c.getDeclaredMethod("m");
//          m.setAccessible(true);      // solution
        Object o = m.invoke(ac);    // IllegalAccessException

        // production code should handle these exceptions more gracefully
    } catch (NoSuchMethodException x) {
        x.printStackTrace();
    } catch (InvocationTargetException x) {
        x.printStackTrace();
    } catch (IllegalAccessException x) {
        x.printStackTrace();
    }
    }
}

调用结果:

$ java MethodTroubleAgain
java.lang.IllegalAccessException: Class MethodTroubleAgain can not access a
  member of class AnotherClass with modifiers "private"
        at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
        at java.lang.reflect.Method.invoke(Method.java:588)
        at MethodTroubleAgain.main(MethodTroubleAgain.java:15)

因为访问修饰符是private所以导致无法调用。

调用invoke()时抛出 IllegalArgumentException

示例:

import java.lang.reflect.Method;

public class MethodTroubleToo {
    public void ping() { System.out.format("PONG!%n"); }

    public static void main(String... args) {
    try {
        MethodTroubleToo mtt = new MethodTroubleToo();
        Method m = MethodTroubleToo.class.getMethod("ping");

        switch(Integer.parseInt(args[0])) {
        case 0:
        m.invoke(mtt);                 // works
        break;
        case 1:
        m.invoke(mtt, null);           // works (expect compiler warning)
        break;
        case 2:
        Object arg2 = null;
        m.invoke(mtt, arg2);           // IllegalArgumentException
        break;
        case 3:
        m.invoke(mtt, new Object[0]);  // works
        break;
        case 4:
        Object arg4 = new Object[0];
        m.invoke(mtt, arg4);           // IllegalArgumentException
        break;
        default:
        System.out.format("Test not found%n");
        }

        // production code should handle these exceptions more gracefully
    } catch (Exception x) {
        x.printStackTrace();
    }
    }
}

运行结果:

$ java MethodTroubleToo 1
PONG!
$ javac MethodTroubleToo.java
MethodTroubleToo.java:16: warning: non-varargs call of varargs method with
  inexact argument type for last parameter;
        m.invoke(mtt, null);           // works (expect compiler warning)
                      ^
  cast to Object for a varargs call
  cast to Object[] for a non-varargs call and to suppress this warning
1 warning
$ java MethodTroubleToo 2
java.lang.IllegalArgumentException: wrong number of arguments
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke
          (NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke
          (DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at MethodTroubleToo.main(MethodTroubleToo.java:21)
$ java MethodTroubleToo 3
PONG!
$ java MethodTroubleToo 4
java.lang.IllegalArgumentException: wrong number of arguments
        at sun.reflect.NativeMethodAccessorImpl.invoke0
          (Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke
          (NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke
          (DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at MethodTroubleToo.main(MethodTroubleToo.java:28)
实际调用的方法抛出异常后抛出 InvocationTargetException 异常

示例:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MethodTroubleReturns {
    private void drinkMe(int liters) {
    if (liters < 0)
        throw new IllegalArgumentException("I can't drink a negative amount of liquid");
    }

    public static void main(String... args) {
    try {
        MethodTroubleReturns mtr  = new MethodTroubleReturns();
        Class<?> c = mtr.getClass();
        Method m = c.getDeclaredMethod("drinkMe", int.class);
        m.invoke(mtr, -1);

        // production code should handle these exceptions more gracefully
    } catch (InvocationTargetException x) {
        Throwable cause = x.getCause();
        System.err.format("drinkMe() failed: %s%n", cause.getMessage());
    } catch (Exception x) {
        x.printStackTrace();
    }
    }
}

运行结果:

$ java MethodTroubleReturns
drinkMe() failed: I can't drink a negative amount of liquid
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-05-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 代码拾遗 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 获取方法的参数名
  • 隐式和合成参数
  • 获取并解析方法修饰符
  • 方法调用
    • 查找指定方法并执行:
    • 问题排查
      • 由于类型擦除导致的 NoSuchMethodException
        • 调用方法是抛出 IllegalAccessException
          • 调用invoke()时抛出 IllegalArgumentException
          • 实际调用的方法抛出异常后抛出 InvocationTargetException 异常
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档