2017-07-19 81 views
1

我有以下几类;Java对象引用问题?

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),然后它会自动覆盖列表中以前添加的项目中的空映射。

有人可以请我解释一下这里展示的这个奇怪的对象引用问题是什么原因造成的。

+1

'payload.getMap()'和'Payload.INSTANCE.getMap()'是完全相同的对象。整个列表中只有一张地图 –

+1

重复并没有真正回答这个问题,因为在这种情况下添加到集合中的所有对象都是不同的。问题归结为无意中使用* shared *实例来代替与空副本不同的* empty *实例。投票重新提出问题。 – dasblinkenlight

回答

4

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

buildPayload方法返回​​被设置为共享实例:

Payload payload = Payload.INSTANCE; 

与此同时,当你通过null有效载荷AjaxRequestBinder构造,该构造使用相同的Payload.INSTANCE

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

您可以通过将Payload构造函数公开并在中创建新实例来修复它10,或使得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方法。