要在HashMap中插入重復的值,首先需要弄清楚HashMap里面是怎么存放元素的。
put方法
Map里面存放的每一個元素都是key-value這樣的鍵值對,而且都是通過put方法進行添加的,而且相同的key在Map中只會有一個與之關聯的value存在。put方法在Map中的定義如下。
V put(K key, V value);
1
put()方法實現:首先hash(key)得到key的hashcode(),hashmap根據獲得的hashcode找到要插入的位置所在的鏈,在這個鏈里面放的都是hashcode相同的Entry鍵值對,在找到這個鏈之后,會通過equals()方法判斷是否已經存在要插入的鍵值對,而這個equals比較的其實就是key。
它用來存放key-value這樣的一個鍵值對,返回值是key在Map中存放的舊value,如果之前不存在則返回null。HashMap的put方法是這樣實現的。
// 在此映射中關聯指定值與指定鍵。如果該映射以前包含了一個該鍵的映射關系,則舊值被替換
public V put(K key, V value) {
// 當key為null,調用putForNullKey方法,保存null與table第一個位置中,這是HashMap允許為null的原因
if (key == null)
return putForNullKey(value);
// 使用hash函數預處理hashCode,計算key的hash值
int hash = hash(key.hashCode());//-------(1)
// 計算key hash 值在 table 數組中的位置
int i = indexFor(hash, table.length);//------(2)
// 從i出開始迭代 e,找到 key 保存的位置
for (Entry<K, V> e = table[i]; e != null; e = e.next) {
Object k;
// 判斷該條鏈上是否有hash值相同的(key相同)
// 若存在相同,則直接覆蓋value,返回舊value
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
// 舊值 = 新值
V oldValue = e.value;
// 將要存儲的value存進去
e.value = value;
e.recordAccess(this);
// 返回舊的value
return oldValue;
}
}
// 修改次數增加1
modCount++;
// 將key、value添加至i位置處
addEntry(hash, key, value, i);
return null;
}
從上我們可以看到在添加對應的key-value這樣的組合時,如果原本已經存在對應的key,則直接改變對應的value,並返回舊的value,而在判斷key是否存在的時候是先比較key的hashCode,再比較相等或equals的。
直接從上面代碼來看是比較的對應Map.Entry的hashCode和key的hashCode,而實際上Map.Entry的hashCode其實就是其存放key的hashCode。而如果對應的key原本不存在的話將調用addEntry將對應的key-value添加到Map中。addEntry傳遞的參數hash就是對應key的hashCode。
實現引用對象作為keys的唯一性
通過對put()方法的研究,我們可以發現,判斷key是否存在的時候是先比較key的hashCode,再比較相等或equals的,所以重寫hashCode()和equals()方法即可實現覆蓋keys的引用(指向具有相同實例變量的對象)。
class MyType {
private String arga;
private String argb;
public MyType(String arga, String argb) {
this.arga = arga;
this.argb = argb;
}
@Override
public int hashCode(){
return this.arga.hashCode() * this.argb.hashCode() ;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof MyType)) {
return false;
}
MyType p = (MyType) obj;
if (this.arga.equals(p.arga) && this.argb.equals(p.argb)) {
return true ;
} else {
return false ;
}
}
}
重寫這兩個方法之后就可以覆蓋重復的引用對象,如果需要對value進行疊加,調用put()方法之前用containsKey()方法判斷是否有重復的鍵值,如果有,則用get()方法獲取原有的value,再加上新加入的value即可。
文章參考自:https://my.oschina.net/elim1/blog/811867
http://blog.csdn.net/dajian790626/article/details/13628137
版權聲明:本文為CSDN博主「山木枝」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/intersting/article/details/72627353