2017-07-19 159 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方法。