Java静态上下文如何引用非静态方法以在实例上调用实现方法序列化
核心实现原理
Java中类名::非静态实例方法的引用形式,会自动把非静态方法隐含的this参数作为函数式接口的第一个入参。你定义的addWood方法签名为void addWood(String s),隐含的this参数类型为Foo,所以Foo::addWood的完整签名是void (Foo, String),刚好匹配BiConsumer<Foo, String>接口的规范,不需要额外改造原有方法。
方案1:使用BiConsumer存储方法引用(推荐,类型安全、无反射开销)
Foo类改造代码
import java.util.function.BiConsumer; import java.util.function.Supplier; import java.util.LinkedHashMap; import java.util.Map; public class Foo { // 静态存储结构,用LinkedHashMap保证调用顺序,Key为你说的全局唯一Parameter Supplier public static final Map<Supplier<String>, BiConsumer<Foo, String>> TASK_REGISTRY = new LinkedHashMap<>(); public void addWood(String s) { /* 原有实现 */ } public void addMetal(String s) { /* 原有实现 */ } public void addFish(String s) { /* 原有实现 */ } public void addFood(String s) { /* 原有实现 */ } public void process() { // 遍历注册的任务,用当前实例调用对应方法 for (Map.Entry<Supplier<String>, BiConsumer<Foo, String>> entry : TASK_REGISTRY.entrySet()) { String param = entry.getKey().get(); entry.getValue().accept(this, param); } } }
外部注册方法的写法
和你预期的写法完全兼容,语法合法:
// parameter就是你说的全局唯一supplier对象 Foo.TASK_REGISTRY.put(parameter, Foo::addWood);
方案2:反射存储Method对象(兼容原有HashMap<Parameter,Method>设计)
如果必须沿用你最初设计的存储Method对象的结构,可以用反射实现:
Foo类改造代码
import java.lang.reflect.Method; import java.util.function.Supplier; import java.util.LinkedHashMap; import java.util.Map; public class Foo { public static final Map<Supplier<String>, Method> TASK_REGISTRY = new LinkedHashMap<>(); public void addWood(String s) { /* 原有实现 */ } public void addMetal(String s) { /* 原有实现 */ } public void addFish(String s) { /* 原有实现 */ } public void addFood(String s) { /* 原有实现 */ } public void process() { try { for (Map.Entry<Supplier<String>, Method> entry : TASK_REGISTRY.entrySet()) { String param = entry.getKey().get(); entry.getValue().invoke(this, param); } } catch (Exception e) { // 按需处理反射异常 throw new RuntimeException(e); } } }
外部注册方法的写法
try { Method addWoodMethod = Foo.class.getMethod("addWood", String.class); Foo.TASK_REGISTRY.put(parameter, addWoodMethod); } catch (NoSuchMethodException e) { // 处理方法不存在的异常 }
- 优先选择方案1,编译期即可校验方法签名正确性,没有反射性能损耗,代码更简洁
- 若必须沿用原有存储
Method的设计,再选择方案2
内容的提问来源于stack exchange,提问作者slit bodmod
相关产品推荐
相关产品推荐

