【问题标题】:Java Object Reference Problems?Java 对象引用问题?
【发布时间】:2017-12-24 17:57:38
【问题描述】:

我有以下课程;

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() 方法时,它会返回一个 AjaxRequestBinder 对象列表,其中每个对象都有;

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

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

有人可以向我解释一下这里展示的这个奇怪的对象引用问题可能是什么原因吗?

【问题讨论】:

  • payload.getMap()Payload.INSTANCE.getMap() 是完全相同的对象。您在列表中只有一张地图
  • 副本并没有真正回答这个问题,因为在这种情况下,添加到集合中的所有对象都是不同的。问题归结为无意中使用 shared 实例代替了 empty 实例,这与副本不同。投票重新提出问题。

标签: java builder object-reference builder-pattern


【解决方案1】:

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

您的buildPayload 方法返回设置为共享实例的payload

Payload payload = Payload.INSTANCE;

同时,当你将null有效载荷传递给AjaxRequestBinder构造函数时,构造函数使用相同的Payload.INSTANCE

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

您可以通过公开Payload 构造函数并在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 方法中清除映射。

【讨论】:

    猜你喜欢
    • 2010-10-11
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-06
    相关资源
    最近更新 更多