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; }
分析:为上面青色字体