You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现存储对象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方法
}

关键修改说明:

  1. 静态模板Map:STATIC_METHOD_TEMPLATE存储未绑定实例的Function(Getter,接收实例返回属性值)和BiConsumer(Setter,接收实例和属性值),仅在类加载时初始化一次。
  2. 实例缓存Map:instanceMethodMap作为实例字段,每个实例仅在第一次调用getNameToGetterSetterMap()时,将静态模板转换为绑定自身的Supplier/Consumer并缓存,后续调用直接返回缓存结果。
  3. 方法引用转换:通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 01:37:03