我正在学习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)
更正了它?
答案 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