Set<String> names = new HashSet<>(); names.add("張三"); names.add(new String("張三")); Iterator<String> iterator = names.iterator(); while(iterator.hasNext()) { System.out.println(iterator.next()); }
以上代碼輸出只有一個:張三
驚不驚喜,意不意外???
下面我們來看原因
按住ctrl鍵點擊add進入到public interface Set<E> extends Collection<E> Set接口中的add抽象方法
boolean add(E e);
然后按住ctrl鍵盤點擊到HashSet類中重新的add方法
public boolean add(E e) { return map.put(e, PRESENT)==null; }
按住ctrl鍵點擊put 進入到HashMap類中的put方法
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
其中的hash(key)是HashMap中的方法
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
返回的值是key.hashCode()的相關轉換,我們就看key.hashCode()的值是什么了 那我們來看一下這個方法
public native int hashCode();//是Object類中的一個抽象方法
其中有繼承重寫這個方法的,但是打開Eclipse就會bug 試了兩次了 ,那我們就不打開了
但是我們可以得到一個結論:
本身HashSet中的hashCode()方法就是同一個對象的hashCode()的返回值是相等的
我們可以自己重寫hashCode()方法來判斷他返回的值
並且其中putVal()方法也在HashMap方法中final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k;
/*
怎么判斷相等的就是用下面的紅色代碼
p.hash==hash 就是調用hash(key)方法后的值,只要是同一個對象,返回值就相同(可以重寫hashCode()方法)
(k = p.key) == key判斷兩個對象的地址是否相同
key.equals(k)默認調用Object類中的equals方法判斷地址是否相同,可以重寫equals方法
如果以上滿足
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
那么這兩個值就是相同的,后來的就會覆蓋前面的。
*/
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } }
if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
分析:為上面青色字體