Java 对象引用问题?

Java Object Reference Problems?

我有以下 类;

public class Payload{

    private Map<String, Object> map;

    public static Payload INSTANCE = new Payload();

    private Payload(){
        map = new HashMap<>();
    }

    public Payload put(String key, Object value){
        map.put(key, value);
        return this;
    }

    public Map<String, Object> getMap(){
        return map;
    }
}

public class AjaxRequestBinder {

    private String url;
    private String method;
    private Map<String, Object> data;
    private String dataType;

    public AjaxRequestBinder(String url, String method, Payload payload, AjaxDataType dataType) {
        this.url = url;
        this.method = method;
        this.data = payload != null ? payload.getMap() : Payload.INSTANCE.getMap();
        this.dataType = dataType != null ? dataType.name() : AjaxDataType.html.name();
    }
    //... getters() & setters()
}

public List<AjaxRequestBinder> getSampleAjaxBinders() throws Exception {
    List<AjaxRequestBinder> requestBinders = new ArrayList<>();
    requestBinders.add(new AjaxRequestBinder(getEndpointURL(ServiceModule.CAT), HttpMethod.GET.name(), null, AjaxDataType.json));
    requestBinders.add(new AjaxRequestBinder(getEndpointURL(ServiceModule.DOG), HttpMethod.GET.name(), null, AjaxDataType.json));
    requestBinders.add(new AjaxRequestBinder(getEndpointURL(ServiceModule.CHICKEN), HttpMethod.GET.name(), null, AjaxDataType.json));
    requestBinders.add(new AjaxRequestBinder(getEndpointURL(ServiceModule.GOAT), HttpMethod.GET.name(), null, AjaxDataType.json));
    requestBinders.add(new AjaxRequestBinder(getEndpointURL(ServiceModule.RABBIT), HttpMethod.POST.name(), buildPayload(ServiceModule.RABBIT, HttpMethod.POST), AjaxDataType.json));
    return requestBinders;
}

public Payload buildPayload(ServiceModule module, HttpMethod httpMethod) throws Exception {
    Payload payload = Payload.INSTANCE;
    module = module != null ? module : ServiceModule.NONE;

    if(httpMethod.equals(HttpMethod.POST)){

        switch(module){
            case CAT:{
                // Do nothing
            }break;
            case DOG:{
                // Do nothing
            }break;
            case CHICKEN:{
                // Do nothing
            }break;
            case GOAT:{
                // Do nothing
            }break;
            case RABBIT:{
                payload.put("color", "white").put("action", "hops");
            }break;
        }
    }else{
        throw new NotYetImplementedException();
    }
    return payload;
}

但是由于一些奇怪的原因,当方法 getSampleAjaxBinders() 被调用时,它 returns 一个 AjaxRequestBinder 对象的列表,每个对象都有;

data = {"color":"white", "action":"hops"}

而只有最后添加的项目才需要这样做。所有之前添加的项目都应该只有 data = {}(空地图)。当我通过该方法进行逐步调试时,我发现在调用 buildPayload(ServiceModule module, HttpMethod httpMethod) 之前一切正常,然后会自动覆盖列表中先前添加的项目中的空映射。

有人可以向我解释是什么导致了这里出现的这个奇怪的对象引用问题吗?

发生这种情况是因为您总是使用 Payload 的单个实例,它恰好是为 RABBIT 设置的。

您的 buildPayload 方法 returns payload 设置为共享实例:

Payload payload = Payload.INSTANCE;

同时,当你将null payload传递给AjaxRequestBinder构造函数时,构造函数使用相同的Payload.INSTANCE:

this.data = payload != null ? payload.getMap() : Payload.INSTANCE.getMap();

您可以通过创建 Payload 构造函数 public 并在 buildPayload 中创建新实例来修复它,或者创建一个单独的空实例 Payload 以供在某些情况下使用当 null 提供给 AjaxRequestBinder 构造函数时:

public static final Payload INSTANCE = new Payload();
// Add this line to Payload
public static final Payload EMPTY = new Payload();
...
// Use EMPTY payload when the caller does not supply an actual one:
this.data = payload != null ? payload.getMap() : Payload.EMPTY.getMap();

请注意,如果继续使用上述共享实例方法,则需要在 buildPayload 方法中清除映射。