如何实现无需反射/Invoke跨类调用监听器并返回指定类型?
实现无反射的监听器调用机制
1. 定义匹配方法签名的函数式接口
先创建一个函数式接口,匹配你需要调用的方法签名(接收CanCreatureAttack参数,返回ListenerReturn),这样就能直接用方法引用注册,完全避开反射:
@FunctionalInterface public interface CreatureAttackListener { ListenerReturn canCreatureAttack(CanCreatureAttack context); }
2. 实现全局静态监听器容器
用一个线程安全的Map存储监听器实例,提供注册和执行的静态方法:
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class ListenerContainer { private static final Map<String, CreatureAttackListener> LISTENER_MAP = new ConcurrentHashMap<>(); // 注册监听器,key用自定义标识(比如类名) public static void register(String key, CreatureAttackListener listener) { LISTENER_MAP.put(key, listener); } // 执行监听器并返回结果 public static ListenerReturn execute(String key, CanCreatureAttack context) { CreatureAttackListener listener = LISTENER_MAP.get(key); return listener != null ? listener.canCreatureAttack(context) : new ListenerReturn(false); } }
3. 改造自定义类并完成注册
修正原类的语法错误,在构造方法中通过方法引用把当前类的逻辑注册到容器:
public class MyCustomClass { public MyCustomClass() { // 注册当前类的canCreatureAttack方法,key指定为"myClassName" ListenerContainer.register("myClassName", this::canCreatureAttack); } public ListenerReturn canCreatureAttack(final CanCreatureAttack canCreatureAttack) { // 修正语法错误:isSuperPlayer后多了括号,ListenerReturn首字母大写 if (canCreatureAttack.getAttacker().isSuperPlayer()) { return new ListenerReturn(true); } // 统一返回ListenerReturn类型,不能直接返回boolean return new ListenerReturn(false); } }
4. 调用监听器的示例
确保MyCustomClass已实例化(构造方法会自动完成注册),之后直接调用容器方法即可:
// 初始化自定义类,自动注册监听器 new MyCustomClass(); // 构造参数并调用监听器 CanCreatureAttack attackContext = new CanCreatureAttack(actor, target); // 注意:return是Java关键字,不能用作变量名 final ListenerReturn result = ListenerContainer.execute("myClassName", attackContext);
核心说明
- 这套方案用函数式接口+方法引用替代反射,本质是把方法转换成接口实例存储,调用时直接执行接口方法,完全不需要反射API。
- 如果需要支持多种类型的监听器,可以定义多个函数式接口,或者用泛型扩展容器的通用性。
- 容器的key可以根据需求调整,比如用类的全限定名、枚举值等,只要保证唯一即可。
内容的提问来源于stack exchange,提问作者Clean code
相关产品推荐
相关产品推荐

