如何实现存储对象Getter/Setter的静态Map版本?
问题描述
现有一个实现了MapPackHelperI接口的SomeStruct类,每次调用getNameToGetterSetterMap()时都会重新创建并填充一个Map,以变量名为键、绑定当前实例的Getter/Setter对为值。由于Getter/Setter逻辑不会在运行时改变,希望将这个Map改为静态共享,避免重复构建,只需传入实例即可操作对应对象的属性。
现有核心代码如下:
接口定义
package main; import org.javatuples.Pair; import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; public interface MapPackHelperI { public Map<String, Pair<Supplier, Consumer>> getNameToGetterSetterMap(); }
实现类代码
package main; import java.util.List; import java.util.Map; import java.util.HashMap; import org.javatuples.Pair; import java.util.function.Consumer; import java.util.function.Supplier; public class SomeStruct implements MapPackHelperI { private long somelong; private String somestring; private List<Float> somelistfloat; private SomeEnum someenum; public Map<String, Pair<Supplier, Consumer>> getNameToGetterSetterMap() { Map<String, Pair<Supplier, Consumer>> nameToGetterSetterMap = new HashMap<>(); nameToGetterSetterMap.put("somelong", Pair.with( this::getSomelong, (Consumer<Long>)this::setSomelong)); nameToGetterSetterMap.put("somestring", Pair.with( this::getSomestring, (Consumer<String>)this::setSomestring)); nameToGetterSetterMap.put("somelistfloat", Pair.with( this::getSomelistfloat, (Consumer<List<Float>>)this::setSomelistfloat)); nameToGetterSetterMap.put("someenum", Pair.with( this::getSomeenum, (Consumer<SomeEnum>)this::setSomeenum)); return nameToGetterSetterMap; } // 以下getter/setter省略(原代码中已定义) }
现有序列化逻辑
public static String serialize(MapPackHelperI objectToSerialize) { Map<String, Pair<Supplier, Consumer>> nameToGetterSetterMap = objectToSerialize.getNameToGetterSetterMap(); for(Entry<String, Pair<Supplier, Consumer>> current : nameToGetterSetterMap.entrySet()) { String name = current.getKey(); Supplier getter = current.getValue().getValue0(); // 基于Getter获取值并序列化的逻辑 } return 序列化结果; }
尝试直接将Map改为静态并使用SomeStruct::getSomelong填充时,编译器报错,需要解决如何实现静态共享模板、同时支持针对不同实例执行Getter/Setter的问题。
解决方案
核心问题在于:this::getXXX是绑定当前实例的方法引用,无法直接存入静态Map共享;而SomeStruct::getXXX是未绑定实例的方法引用,需要适配为绑定特定实例的Supplier/Consumer才能符合原接口的要求。
方案1:静态模板+实例缓存(保持原接口不变)
修改SomeStruct类,用静态Map存储未绑定实例的方法引用模板,同时为每个实例缓存绑定自身的Getter/Setter Map,避免重复构建:
package main; import java.util.List; import java.util.Map; import java.util.HashMap; import org.javatuples.Pair; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.function.Function; import java.util.function.BiConsumer; public class SomeStruct implements MapPackHelperI { private long somelong; private String somestring; private List<Float> somelistfloat; private SomeEnum someenum; // 静态共享的方法引用模板:存储未绑定实例的Getter和Setter private static final Map<String, Pair<Function<SomeStruct, ?>, BiConsumer<SomeStruct, ?>>> STATIC_METHOD_TEMPLATE; // 实例级缓存:存储绑定当前实例的Getter/Setter对 private Map<String, Pair<Supplier<?>, Consumer<?>>> instanceMethodMap; // 静态初始化模板Map static { STATIC_METHOD_TEMPLATE = new HashMap<>(); STATIC_METHOD_TEMPLATE.put("somelong", Pair.with(SomeStruct::getSomelong, SomeStruct::setSomelong)); STATIC_METHOD_TEMPLATE.put("somestring", Pair.with(SomeStruct::getSomestring, SomeStruct::setSomestring)); STATIC_METHOD_TEMPLATE.put("somelistfloat", Pair.with(SomeStruct::getSomelistfloat, SomeStruct::setSomelistfloat)); STATIC_METHOD_TEMPLATE.put("someenum", Pair.with(SomeStruct::getSomeenum, SomeStruct::setSomeenum)); } @Override public Map<String, Pair<Supplier<?>, Consumer<?>>> getNameToGetterSetterMap() { // 仅在第一次调用时初始化缓存 if (instanceMethodMap == null) { instanceMethodMap = new HashMap<>(); for (Map.Entry<String, Pair<Function<SomeStruct, ?>, BiConsumer<SomeStruct, ?>>> entry : STATIC_METHOD_TEMPLATE.entrySet()) { String key = entry.getKey(); Function<SomeStruct, ?> getterFunc = entry.getValue().getValue0(); BiConsumer<SomeStruct, ?> setterBiConsumer = entry.getValue().getValue1(); // 将未绑定的方法引用转换为绑定当前实例的Supplier/Consumer Supplier<?> getter = () -> getterFunc.apply(SomeStruct.this); Consumer<?> setter = value -> setterBiConsumer.accept(SomeStruct.this, value); instanceMethodMap.put(key, Pair.with(getter, setter)); } } return instanceMethodMap; } // 以下getter/setter方法保持不变 public long getSomelong() { return this.somelong; } public void setSomelong(long somelong) { this.somelong = somelong; } public String getSomestring() { return this.somestring; } public void setSomestring(String somestring) { this.somestring = somestring; } public List<Float> getSomelistfloat() { return this.somelistfloat; } public void setSomelistfloat(List<Float> somelistfloat) { this.somelistfloat = somelistfloat; } public SomeEnum getSomeenum() { return this.someenum; } public void setSomeenum(SomeEnum someenum) { this.someenum = someenum; } // ... hashcode, toString, equals方法 }
关键修改说明:
- 静态模板Map:
STATIC_METHOD_TEMPLATE存储未绑定实例的Function(Getter,接收实例返回属性值)和BiConsumer(Setter,接收实例和属性值),仅在类加载时初始化一次。 - 实例缓存Map:
instanceMethodMap作为实例字段,每个实例仅在第一次调用getNameToGetterSetterMap()时,将静态模板转换为绑定自身的Supplier/Consumer并缓存,后续调用直接返回缓存结果。 - 方法引用转换:通过Lambda表达式将未绑定的
Function/BiConsumer包装为绑定当前实例的Supplier/Consumer,符合原接口的返回类型要求。
方案2:直接使用静态模板(修改序列化逻辑)
如果可以调整序列化逻辑,放弃对MapPackHelperI接口的依赖,可直接使用静态模板Map,传入实例执行操作,完全避免Map的重复构建:
public static String serialize(SomeStruct objectToSerialize) { Map<String, Pair<Function<SomeStruct, ?>, BiConsumer<SomeStruct, ?>>> methodTemplate = SomeStruct.STATIC_METHOD_TEMPLATE; for (Map.Entry<String, Pair<Function<SomeStruct, ?>, BiConsumer<SomeStruct, ?>>> entry : methodTemplate.entrySet()) { String fieldName = entry.getKey(); Function<SomeStruct, ?> getter = entry.getValue().getValue0(); Object fieldValue = getter.apply(objectToSerialize); // 执行序列化逻辑 } return 序列化结果; }
这种方式无需创建任何实例级Map,直接复用静态模板,性能最优,但需要修改现有调用逻辑。
内容的提问来源于stack exchange,提问作者Smrt
相关产品推荐
相关产品推荐

