084.JAVA反射机制_通过反射获取和操作类方法


博主的 Github 地址


1. 获取和操作类方法

  • 获取和操作类方法分为三个步骤:
    • 首先获取目标类的字节码文件
    • 然后获取字节码对象中的目标类方法
    • 最后通过类对象来调用目标类方法

1.1. Class 类中获取类方法的方法

1.1.1. getMethods() 方法
  • 定义:
    public Method[] getMethods()

  • 作用:
    返回该类中所有 public 方法, 并以 Method 数组的形式返回.
    这些 public 方法包含从父类和接口中所继承的方法.

1.1.2. getDeclaredMethods() 方法
  • 定义:
    public Method[] getDeclaredMethods()

  • 作用:
    返回该类中所有方法, 并以 Method 数组的形式返回, 无视访问权限进行获取.
    但这些方法并不包含从父类或接口中所继承的方法.

1.1.3. getMethod(String name, Class<?>... parameterTypes) 方法
  • 定义:
    public Method getMethod(String name, Class<?>... parameterTypes)

  • 作用:
    获取该类中所指定的一个 public 方法, 获取方法的范围包括从父类或接口中继承的.

  • 参数:

    • name - 方法名
    • parameterTypes - 参数表中参数的 Class 类型
1.1.4. getDeclaredMethod(String name, Class<?>... parameterTypes) 方法
  • 定义:
    public Method getMethod(String name, Class<?>... parameterTypes)

  • 作用:
    获取该类中所指定的一个方法, 无视访问权限获取,
    但获取方法的范围不包括从父类或接口中继承的.

  • 参数:

    • name - 方法名
    • parameterTypes - 参数表中参数的 Class 类型

1.2. Method 类中操作类方法的方法

  • java.lang.reflect.Method
  • 该类也有从父类中继承控制访问权限的方法, 操作和构造器中的相似.
1.2.1. invoke(Object obj, Object... args) 方法
  • 定义:
    public Object invoke(Object obj, Object... args)

  • 作用:
    对带有指定参数的指定对象调用由此 Method 对象表示的底层方法.

  • 参数:

    • obj - 从中调用底层方法的对象
    • args - 用于方法调用的参数
  • 返回:
    使用参数 args 在 obj 上指派该对象所表示方法的结果, 以 Object 的形式返回.

  • 备注:

    • 如果底层方法是静态的, 那么可以忽略指定的 obj 参数. 该参数可以为 null.
    • 如果底层方法所需的形参数为 0, 则所提供的 args 数组长度可以为 0 或 null.

1.3. Method 操作方法补充

1.3.1. 使用反射调用数组参数方法
  • 假设存在如下方法

    public static void test(int...arr){}
  • 方法中参数表存在可变参数, 实际可变参数是数组,
    所以需要按照如下方式进行获取和调用方法.

    Method m = cls.getMethod("test", int[].class);
    m.invoke(null, new int[] {1, 2, 3});
  • 如果以这种方式传递参数: m.invoke(null, 1, 2, 3);
    也会报错, 因为传递的参数必须严格按照规则来传递,
    可变参数实际本身是数组, 因此必须传递数组.

  • 然而对于有的数据类型的数组会被自动解包, 例如 String 类型.
    假设存在如下方法:

    public static void te5t(String[] arr){}
  • 获取方法后如果进行如下参数传递, 会发生错误.

    Method m1 = cls.getMethod("te5t", String[].class);
    m1.invoke(null, new String[] {"1", "3"});
  • 这是因为这个数组被自动解包了, 导致其恢复成一个个单独的元素.
    因此会被视为传入的是一个个 String 元素, 而非数组元素, 导致错误.

  • 解决方案:

    • 由于 invoke() 方法中第二个参数是 Object 可变参数,
      即实际上第二个参数要求传入的是 Object 类型的数组.

    • 所以可以将数据都包装进 Object 数组中, 再进行传递.
      这样传递绝对符合要求, 不会发生错误.

      Method m1 = cls.getMethod("te5t", String[].class);
      m1.invoke(null, new Object[] {new String[] {"1", "3"}});
      
      Method m = cls.getMethod("test", int[].class);
      m.invoke(null, new Object[] {new int[] {1, 2, 3}});
  • 因此调用带有数组参数的方法的时候都建议统一使用这种形式传参.

1.3.2. 使用反射获取泛型参数方法
  • 泛型会自动提升为 Object 类型, 因此获取的时候以 Object 类型看待.
  • 例如存在如下包含泛型参数的方法:
    public static <T> void t3st(T... arr){}
  • 获取该方法时, 直接使用 Object 类型即可.
    Method m2 = cls.getMethod("t3st", Object[].class);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值