HashMap和HashSet深度解析
package container;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
/**
* @author jiq408694711@163.com
*
* 測試HashSet中,通過equals方法檢測到重複之後會發生什麼。
* 以及測試hashCode函式生成的雜湊碼相同之後,會不會被去掉。
*
*/
class TestObject{
int x;
int y;
public TestObject(int x, int y){
this.x = x;
this.y = y;
}
/* 一般重寫equals方法的同時也會重寫hasCode方法,為什麼? */
public int hashCode(){
return x;
}
/* 注意引數是Object型別,否則就不是覆蓋了 */
public boolean equals(Object obj) {
TestObject oo = (TestObject)obj;
return (this.x == oo.x)?true:false;
}
}
public class HashSetTest {
public static void main(String args[]){
/**
* 重寫了Object的equals方法,只要兩個物件x欄位相等,
* 那麼兩個物件就相等。(預設的equals方法是比較引用==)
* (注意: 引用仍然不同,即不是指向同一個物件)
*/
TestObject o1 = new TestObject(1,3);
TestObject o2 = new TestObject(3,3);
System.out.println(o1.equals(o2));
System.out.println(o1 == o2);
/**
* HashMap,採用陣列雜湊儲存,雜湊值有hashCode返回,
* 同一個hashCode的物件,採用連結法解決衝突。通過equals判斷是否衝突。
* 下面是HashMap內部的put方法的實現。
* public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode()); //生成hash值
int i = indexFor(hash, table.length); //找到該hash值在陣列中位置索引
//迴圈該hash槽的所有物件
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//如果equals()方法返回true,發現“重複”
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value; //將新的值替換原來的值,鍵不動
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
* */
HashMap<TestObject,String> map = new HashMap<TestObject,String>();
//鍵hashCode相同,且equals返回true,故替換值,可以看到鍵沒有變化
map.put(new TestObject(1,0), "XXX");
map.put(new TestObject(1,2), "YYY");
System.out.println("MAP SIZE:"+map.size());
for(Entry<TestObject,String> e: map.entrySet()){
System.out.println(e.getKey().x+","+e.getKey().y+","+e.getValue());
}
/**
* HashSet通過HashMap實現,鍵就是插入的物件,而值統一是一個static的Object
* 下面是add方法的實現。
* public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
* */
HashSet<TestObject> set = new HashSet<TestObject>();
set.add(new TestObject(1,2));
//hashCode方法和equals方法都返回相同值,所以替換值,但是它的值部分只是一個static的Object
set.add(new TestObject(1,1));
set.add(new TestObject(3,1));
set.add(new TestObject(3,4));
System.out.println("SET SIZE:"+set.size());
for(TestObject o: set){
System.out.println(o.x+","+o.y);
}
/*
* 注意,HashCode返回的值決定了你的存在雜湊表中的Entry物件應該在哪個槽位
* 設想如果你的equals方法重寫了,認為兩個物件相等,但是hashCode返回的兩個物件
* 的值卻不一樣,那麼他們都不可能在一個槽位,所以equals方法就沒意義。
*
* 所以我們重寫鍵物件的equals方法的時候,一般同時重寫hashCode方法。
* 儘量保證:
* (1)當obj1.equals(obj2)為true時,obj1.hashCode() == obj2.hashCode()必須為true
* (2)當obj1.hashCode() == obj2.hashCode()為false時,obj1.equals(obj2)必須為false
*/
/**
* 擴充: 如果吧TestObject的equals方法改成return (this.y == oo.y)?true:false;
* 那麼 set.add(new TestObject(1,2));
set.add(new TestObject(1,1));
set.add(new TestObject(3,1));
會發生什麼?輸出set大小是多少?答案是3
* 因為前兩個物件雖然hashCode相同,但是equals返回false,故不是衝突的物件
* 後兩個雖然equals返回了true,但是不是存在同一個槽位的物件,故也不是衝突物件。
* */
}
}
輸出:
false
false
MAP SIZE:1
1,0,YYY
SET SIZE:2
1,2
3,1
相關文章
- HashSet和HashMapHashMap
- 深度解析HashMapHashMap
- Java HashMap 和 HashSet 的高效使用技巧JavaHashMap
- HashSet與HashMap的區別HashMap
- HashMap、LinkedHashMap、HashTable、HashSet筆記HashMap筆記
- 集合框架-HashMap&HashSet&LinkedHshMap框架HashMap
- 深度解析HashMap集合底層原理HashMap
- HashSet/HashMap、TreeSet/TreeMap、LinkedHashSet/LinkedHashMap 區別HashMap
- 深度解析HashMap底層實現架構HashMap架構
- HashMap底層實現原理/HashMap與HashTable區別/HashMap與HashSet區別HashMap
- 語言小知識-Java HashMap類 深度解析JavaHashMap
- HashMap深度分析HashMap
- 你真的瞭解HashSet 和HashMap的區別、優缺點、使用場景嗎?HashMap
- HashMap原始碼解析和設計解讀HashMap原始碼
- HashSet、TreeSet、CopyOnWriteArraySet和CopyOnWriteArrayList
- HashSet與HashMap比較——新增物件已存在處理方式一樣?HashMap物件
- Java——HashMap原始碼解析JavaHashMap原始碼
- Java7/8中的HashMap和ConcurrentHashMap全解析JavaHashMap
- Android技術棧(五)HashMap和ArrayMap原始碼解析AndroidHashMap原始碼
- RecyclerView用法和原始碼深度解析View原始碼
- android解析HashMap格式的jsonAndroidHashMapJSON
- HashSet中重寫haseCode和equals
- Java併發指南13:Java 中的 HashMap 和 ConcurrentHashMap 全解析JavaHashMap
- Hashtable和HashMapHashMap
- HashSet
- HashMap 、ConcurrentHashMap知識點全解析HashMap
- HashMap原始碼解析(java1.8.0)HashMap原始碼Java
- 詳解HashMap原始碼解析(下)HashMap原始碼
- 詳解HashMap原始碼解析(上)HashMap原始碼
- 深度解析深拷貝和淺拷貝
- 深度解析Hashtable
- Java集合(6)之 HashMap 原始碼解析JavaHashMap原始碼
- 乾貨:HashMap的工作原理解析HashMap
- 深度解析!Linux 命令 su 和 sudo 的區別Linux
- Java HashMap 原始碼逐行解析(JDK1.8)JavaHashMap原始碼JDK
- JDK1.8_HashMap原始碼__tableSizeFor方法解析JDKHashMap原始碼
- Java集合詳解(三):HashMap原理解析JavaHashMap
- Java併發指南13:Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析JavaHashMap
- Flutter原理深度解析Flutter