456. Java 反射 - 浅层方法访问

456. Java 反射 - 浅层方法访问

在前面的课程中,我们学习了如何获取对象的 Class,现在我们来探索 如何通过 Reflection 获取类的方法,并调用它们


1. 查看类的所有方法

我们可以使用 Class.getMethods() 获取某个类的 所有公共方法(包括继承的接口方法和父类方法):

import java.util.Iterator;
import java.util.stream.Stream;

public class MethodsOnIterator {
    public static void main(String[] args) {
        Stream.of(Iterator.class.getMethods())
              .forEach(System.out::println);
    }
}

输出示例(以 Java 21 为例):

public default void java.util.Iterator.remove()
public default void java.util.Iterator.forEachRemaining(java.util.function.Consumer)
public abstract boolean java.util.Iterator.hasNext()
public abstract java.lang.Object java.util.Iterator.next()

说明

  • 可以看到迭代器的方法包括抽象方法和默认方法
  • Reflection 可以让我们在运行时访问这些方法,并调用它们

2. 通过 Reflection 调用方法

假设我们想调用 IteratorforEachRemaining 方法:

import java.util.List;
import java.util.Iterator;
import java.util.function.Consumer;

public class MethodsOnIteratorCalling {
    public static void main(String[] args) throws ReflectiveOperationException {
        // 创建一个迭代器
        Iterator<String> iterator = Arrays.asList("Hello", "Dev", "Java").iterator();

        // 1. 获取 forEachRemaining 方法
        // 注意:需要指定参数类型的 Class 对象
        Method forEachRemainingMethod = Iterator.class.getMethod("forEachRemaining", Consumer.class);

        // 2. 准备参数:定义一个 Consumer 用于打印
        Consumer<String> println = System.out::println;

        // 3. 调用方法
        // invoke(对象实例, 参数...)
        forEachRemainingMethod.invoke(iterator, println);
    }
}

注意事项

  • 可能会抛出异常,如 NoSuchMethodExceptionIllegalAccessException
  • Java 7 引入 ReflectiveOperationException,覆盖了所有反射相关异常

3. 动态调用静态方法

Reflection 还可以用来 动态调用静态方法,即使我们在编写代码时并不知道具体方法。下面是一个实战示例:

3.1 目标

  • 对一个数字列表进行操作
  • Collections 类中查找所有返回类型为 void、参数为 List 的方法
  • 调用这些方法并观察效果

3.2 示例代码

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class CollectionsListMethods {
    public static void main(String[] args) throws ReflectiveOperationException {
        // 1. 准备数据:将 π 的前 16 位数字拆分为 List<Integer>
        String piStr = "3141592653589793";
        List<Integer> pi = piStr.chars()
                .map(c -> c - '0')
                .boxed()
                .collect(Collectors.toList());

        System.out.println("原始列表: " + pi);

        // 2. 遍历 Collections 的所有公共方法
        for (Method method : Collections.class.getMethods()) {
            // 筛选条件:
            // 1. 返回值为 void
            // 2. 参数个数为 1
            // 3. 参数类型为 List
            if (method.getReturnType() == void.class
                    && method.getParameterCount() == 1
                    && method.getParameterTypes()[0] == List.class) {

                System.out.println("调用方法: " + method.getName());

                // 3. 调用静态方法
                // 注意:调用静态方法时,invoke 的第一个参数传 null
                method.invoke(null, pi);

                System.out.println("结果: " + pi);
                System.out.println("---");
            }
        }
    }
}

3.3 输出示例

原始列表: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3]
调用方法: reverse()
[3, 9, 7, 9, 8, 5, 3, 5, 6, 2, 9, 5, 1, 4, 1, 3]
调用方法: sort()
[1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 7, 8, 9, 9, 9]
调用方法: shuffle()
[5, 7, 4, 9, 9, 9, 2, 1, 6, 5, 3, 3, 1, 5, 3, 8]

说明

  • 找到了三个匹配方法:reverse(), sort(), shuffle()
  • 静态方法的调用不依赖实例,invoke(null, args…)
  • 这种方式可以用于动态处理集合或调用工具类方法

4. 总结

  1. Reflection 可以访问类的所有公共方法
  2. 可以动态调用实例方法和静态方法
  3. 异常处理
    • ReflectiveOperationException 统一处理反射异常
  4. 应用场景
    • 框架动态调用方法(如 ORM、注解处理)
    • 工具类通用操作(如自动排序、集合操作)
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容