HashSet中的add()方法的执行过程。
HashSet sets = new HashSet();
set.add()不能添加重复数据,具体原因如下:
例如:
public class Test {
public static void main(String[] args) {
HashSet<Object> sets = new HashSet<Object>();
sets.add(“tom”);
sets.add(“tom”);
System.out.println(sets.size());
}
}
输出的set长度将是1。
HashSet<Object> sets = new HashSet<Object>();
首先在sets.add(“tom”);sets.add(“tom”);两行打断点。
Debug运行,按F5进入add()内,
此处map指向HashSet()
再点F5进入该方法
此处hash()将在本类下面用到
此处在627行打断点按F6运行至此,详细代码如下:
627 if ((tab = table) == null || (n = tab.length) == 0)
628 n = (tab = resize()).length;
629 if ((p = tab[i = (n - 1) & hash]) == null)
630 tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
633 if (p.hash == hash &&
634 ((k = p.key) == key || (key != null && key.equals(k))))
635 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;
}
646 if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
652 if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
661 if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
第一次传入tom时
627行,table是全局变量,传入值为null
628行,n的值为16(等式右边的默认值)
629行,此处hash将调用如下代码,此处tab[i = (n - 1) & hash]将为null(第一次传入时为空)代码向下运行,
630行, 为tab[i]赋值
代码运行至661行及以下,结束!
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
第二次传入tom时
此时table在上一次628行执行后将不为null,627行不会进入,因(n = tab.length) == 0),此时tab[i = (n - 1) & hash]中i = (n - 1) & hash与上次结果一样,但tab已不为空;将直接进入633行,
此处,前后两次获取的hash相等(String中同一变量调用的hash返回值相同),e=p ,代码进入652行改写value后结束(不用管这个),第二次的tom未存进去。所以set里面只有一个tom
以上即为HashSet中add的执行过程。