2013-05-30 61 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; 
相关问题