映射,在使用put时重用可变密钥

时间:2013-05-30 13:14:43

标签: java

为了只对地图进行一次查找并尽可能多地重用我的密钥实例,我想知道这样做是否合法:

    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;
    }
}

我只用put进行一次地图查找。 但我可以重用GroupByOrdKey实例吗? Javadoc没有说清楚,值被替换但关键实例呢?

是否存在允许此类用例的其他Map实现:

  • 只有一个地图查找
  • 重用现有密钥实例

由于

2 个答案:

答案 0 :(得分:3)

您应该避免在哈希映射中使用可变键。至少,您需要推迟已添加到哈希映射中的密钥的变异,直到将其从地图中删除为止。否则,变异的密钥将变为&#34;无法访问&#34;在地图内。

考虑这一系列事件(为简单起见,假设int的哈希码是int本身):

  • 创建一个值为5
  • 的可变整数key
  • key添加到哈希映射中;它将被散列到对应于代码为5
  • 的存储桶中
  • key设置为6
  • 尝试再次将key添加到地图中。此时,密钥将被散列到存储桶以获取6的哈希码,并再次添加到地图中。
  • 创建一个查询键queryKey,一个值为5的可变整数。尝试用它搜索哈希映射。

此时,queryKey的{​​{1}}将不再是&#34; connect&#34;到5的旧密钥,即使它们具有相同的哈希码:位于5的哈希桶中的key实例也不会与5相等},因为queryKey的当前值为key。实际上,旧密钥及其关联的映射条目变得无法访问。

答案 1 :(得分: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;