2013-05-30 44 views
2

爲了使只有一個查找地圖和重用盡可能我的鑰匙情況下,我想知道這是否是合法的,做到這一點:地圖,使用時再用一個可變的鑰匙放在

public static class GroupByOrdMap { 
     private final Map<GroupByOrdKey, MutableInt> map = new HashMap<>(); 

     /** 
     * Increment the value previously associated to key. 
     * or add a new entry with value 1. 
     * @param key the key 
     * @return a reusale GroupByOrdKey or null if there is nothing to reuse 
     */ 
     public GroupByOrdKey inc(GroupByOrdKey key) { 
      MutableInt mu = new MutableInt(1); 
      MutableInt prev = map.put(key, mu); 
      if(prev != null) { 
       mu.add(prev); // increment existing value 
       // XXX : this key is mutable, but can I safely reuse this instance??? 
       return key; 
      } 
      return null; 
     } 
    } 


// Key, as it can be heavy I would like to reuse it as much as possible 
public static class GroupByOrdKey { 
    private long[] ords; 

    public GroupByOrdKey(int size) { 
     ords = new long[size]; 
    } 

    private void setOrd(int idx, long ord) { 
     ords[idx] = ord; 
    } 

    @Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result + Arrays.hashCode(ords); 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     GroupByOrdKey other = (GroupByOrdKey) obj; 
     if (!Arrays.equals(ords, other.ords)) 
      return false; 
     return true; 
    } 
} 

我只用一個地圖查找。 但我可以重用GroupByOrdKey實例嗎? Javadoc沒有說清楚,價值被取代了,但關鍵實例呢?

是否有任何其他Map實現允許這樣的用例:

  • 只有一個地圖查找
  • 重用現有的密鑰實例

感謝

+0

從這個問題,如果你真的想變異的關鍵它在地圖中使用後,是有些不清楚的代碼? (請參閱下面的dasblinkelights答案)。我建議通過將'ords'聲明爲final來使'GroupByOrdKey'不可變,並且只在構造函數中初始化它。這會打破你的設計嗎? –

+0

重用未使用的密鑰的想法是重用ords數組,所以它不會破壞設計,但我會創建許多ords []數組。 – nomoa

回答

3

您應該避免使用可變密鑰中哈希映射。至少,您需要推遲已添加到哈希映射中的密鑰的變體,直到它從地圖中移除爲止。否則,變異鍵將在地圖內變得「不可達」。

考慮事件序列(假設爲簡單起見,一個int的散列碼是int本身):

  • 創建一個可變的整數key具有5
  • 值添加key到散列映射;它將被散列到對應於代碼爲5的代碼塊
  • 將代碼key設置爲6
  • 嘗試再次將key添加到地圖。此時,密鑰將被哈希到散列碼爲6的哈希碼,並再次添加到地圖中。
  • 創建一個查詢鍵queryKey,一個值爲5的可變整數。嘗試使用它搜索哈希映射。

在這一點上,5queryKey將不再「連接」到5舊密鑰,即使它們具有相同的散列碼:中key坐的5的散列桶不會比實例等於queryKey,因爲key的當前值爲6。本質上,舊密鑰及其關聯的映射條目變得無法訪問。

+0

基本上是正確的答案,但也許這個問題是誤導性的:從給出的例子,我看不到地圖鍵的變異!所以我會說nomoas代碼片段看起來不錯。 –

+0

GroupByOrdMap#inc javadoc聲明用戶可以重用密鑰實例(特別是long [] ords數組)。要評論dasblinkenlight響應:讓我重新說明一下我的問題:如果替換值,Map.put(K鍵,V值)在「鍵」實例中執行了什麼? – nomoa

+0

@GyroGearless你說的對,代碼片段不會揭示關鍵字的變化,只會顯示值的變化,這是100%有效的。然而,這個問題是關於重用現有的關鍵實例(大概是在對它們進行變異之後),這需要非常謹慎的執行(即在變異之前必須插入和移除關鍵字)。由此產生的代碼也會非常脆弱:一個善意的同事可以通過對使用可變鍵的代碼的看似無害的修改來打破它。 – dasblinkenlight

0

它可能工作,但它幾乎肯定不會攜帶。究其原因 - 這很可能是某處HashMap代碼會出現:

... 
if (thisKey == thatKey) { 
    // They are the same object - they MUST be equal. 
    ... 
    code that will not be executed for you but you probably wish it was 
} 

,如果沒有在你有可能是別人。

事實上,它看起來像你這樣做你自己在你的equals方法:

... 
    if (this == obj) 
     return true; 
相關問題