情况1添加一个直接赋值的字符
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
进入HashSet add方法。返回值为boolean。对象map调用put方法。看put方法的返回值是否为空。来返回true,false
public HashSet() {
map = new HashMap<>();
}
private transient HashMap<E,Object> map;
点入map对象,发现map是由HashMap创建的对象。所以HashSet的add方法实质上是调用的HashMap的put方法。
private static final Object PRESENT = new Object();
而map的put方法需传入两个参数,e为调用add时传入的,PRESENT为源代码中定义的常量
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
进入put方法。参数key为add方法时添加的数据,value为PRESENT常量。有返回值为V类型的值 。进入hash方法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
是个静态final方法。传入key参数。int一个h来接收key的hashCode,hashCode方法有特定的公式来计算后返回数据的hashCode值,hash方法基于hashCode经过运算后返还。我这里把hash(key)理解成一个key的特殊地址。
回到put方法。进入putVal方法
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) //此为putVal方法的定义{
Node<K,V>[] tab; Node<K,V> p; int n, i;//创建一个名为tab的Node数组。
if ((tab = table) == null || (n = tab.length) == 0)//table为一个全局变量,由Node数组创建是一个空数组。//tab和table指向同一个地址,所以(tab=table)==null为true。
n = (tab = resize()).length;//resize()的返回值默认长度为16.
if ((p = tab[i = (n - 1) & hash]) == null)//n为16,16减一为15.按位与hash值不为空所以为ture
tab[i] = newNode(hash, key, value, null);//key为add加的数据,value为一个常量(PRESENT)和对应的hash赋值 数组tab[i];
else {
Node<K,V> e; K 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;//执行完上一个if后,直接在这里返回null。所以map.put()==null成立。返回true 添加成功}
情况2 第二次直接赋相同值时
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)//第二次赋值时,table为16不为null.
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)//n还是16,因为第二次赋的值相同所以hash值也相同,所以i也一样
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;//因为两次的值hash值一样。所以将p中的第一次的值赋值给e;
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//e中有第一次的值。所以不为null,所以为true
V oldValue = e.value;//将e的value传给 oldvalue
if (!onlyIfAbsent || oldValue == null)//onlyIfAbsent为put 方法传进来的false.前面有个!所以为true。
e.value = value;//hashSet add添加的数据对应hashMap的key。所以value对hashSet没什么意义。
afterNodeAccess(e);
return oldValue;//返回值oldValue,结束该方法。
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
浙公网安备 33010602011771号