Java HashMap是否要求值是不可变的?

时间:2015-07-04 07:14:56

标签: java hashmap

我正在学习Java HashMap类(Key,Value),并找到为什么Key需要Immutable,好像它被添加到哈希后更改它可能在错误的存储桶中

但是Value呢?是否需要Immutable

我最近遇到了一个问题,当我使用containsKey() AtomicInteger方法时,我遇到了奇怪的行为(addAndGet()中没有在地图中返回的键)改变价值。

然后,当我需要更改与键对应的值并解决问题时,我切换到放置new Integer()

修改

这只是要求Immutable,但这里是代码:

`

HashMap<Long , PreparedStatement> hash_map= new HashMap<Long, PreparedStatement>(); 
HashMap<Long , Integer> hash_map_count = new HashMap<Long , Integer>();

//some code here , lets say phone value comes to a function and function contains this code

 if(hash_map.containsKey( phone)) // present
        {
            ps_insert = (PreparedStatement)hash_map.get( phone);
            count_temp = hash_map_count.get( phone);

            if(count_temp == null)
            {
                System.out.println("************"+ phone);

            }

            count_temp.addAndGet(1); //no need to re-insert into map as value changed by +1 here.
        System.out.println("count : "+count_temp.get()); // 

    }
    else
    {
        ps_temp = conn.prepareStatement("INSERT into T_"+ phone+" VALUES (?,?,?,?,?,?,?)");
        hash_map.put( phone,ps_temp);
        count_temp = new AtomicInteger(1);
        hash_map_count.put( phone, count_temp);
        ps_insert = ps_temp;
        System.out.println("new phone :"+ phone+" count :"+count_temp.get());
    }

问题是******在count_temp中打印了电话(即我得到了null)。当我为手机插入AtomicInteger时,这是可能的 然后我检查了一下,发现手机从未插入到哈希地图中,但containsKey()仍为此返回true。

现在任何人都可以解释为什么会发生这种情况以及为什么更改为Integer()并插入new Integer(changed value)更正了它?

2 个答案:

答案 0 :(得分:5)

可以修改地图的价值。

还可以修改密钥。密钥需要遵循修改之前和之后equals()hashCode()的条件将得到相同的结果(在equals()的情况下具有相同的输入值)。此外,如果可以修改密钥,通常它们是不可修改的。

为了更好地说明密钥可以修改的原因,我添加了一些关于HashMap如何工作以及如何编码ModifiableKey的解释。

如何使用HashMap:

在内部,HashMap使用Entry数组,其中Entry是一个tern(Key,Value,Entry)。

table

0 --> {K, V, E} --> {K, V, null}
1 --> {k, V, null}
2
3
4 --> {K, V, null}
5

以下是get()

的代码
 public V get(Object key) {
     if (key == null)
        return getForNullKey();
     int hash = hash(key.hashCode());
     for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
         Object k;
         if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
             return e.value;
     }
     return null;
 }

如您所见,首先计算密钥的hashCode。然后使用hashCode在表中查找索引。如果地图中存在a Key,则可以通过该位置的Entry元素的链接列表来循环。 要检查该密钥是否存在,使用equals()方法(在for循环内)。

如何构建可在地图中使用的可修改密钥

因此,假设您希望将以下类用作密钥。

public class ModifiableKey {
    private String unmodifiablePart;
    private String modifiablePart;


    public ModifiableKey(String unmodifiablePart) {
        this.unmodifiablePart = unmodifiablePart;
    }

    public String getUnmodifiablePart() {
        return unmodifiablePart;
    }

    public boolean equals(Object obj) {
        ModifiableKey mk = (ModifiableKey) obj;
        return unmodifiablePart.equals(mk.getUnmodifiablePart());
    }

    public int hashCode() {
        return unmodifiablePart.hashCode();
    }

    public void setModifiablePart(String modifiablePart) {
        this.modifiablePart = modifiablePart;
    }

    public String getModifiablePart() {
        return modifiablePart;
    }
}

这个类是可修改的。您可以根据需要更改属性modifiablePart的值。但它可以用作地图的关键字 equals并且hashCode在modifiablePart更改值时不会改变它们的行为。

答案 1 :(得分:0)

首先,您在其他地图上调用containesKey,然后从另一个地图获取值。这就是为什么您在这里得到不同结果的原因。

if(hash_map.containsKey( phone))
   count_temp = hash_map_count.get( phone);
        if(count_temp == null)

第二,值在HashMap中不需要是不变的。但是密钥必须是不变的。但是map不会在其上强加任何规则,但是如果key不可变,那么您可能会在map中看到意外的行为。只有确保确保在初始化后再也不要更改在hashcode()和equals()中使用的键类中的实例属性,才能在map中具有可变键。 有关更多详细信息,请参阅下面的博客。 why-hashmap-key-should-be-immutable