HashSet中add()方法的执行过程分析

HashSet中add()方法的执行过程分析

一、在HashSet中添加一个String类型的数据,具体步骤如下:

HashSet<String> set = new HashSet<>();
	set.add("Tom");//HashSet存储的数据实际上存在了HashMap的key中   //(1)
	set.add("Tom");//(2)
	set.add("Lucy");//(3)

二、执行过程的步骤
1、创建一个HashSet类

HashSet<String> set = new HashSet<>();

2、在HashSet中创建一个map对象

 public HashSet() {
        map = new HashMap<>();
 }

3、将在HashSet中添加的数据存储到HashMap的key中,add(E e)为HashSet类中的方法

public boolean add(E e) {
	return map.put(e, PRESENT)==null;//返回put方法
}

4、put(K key, V value)为HashMap类中的方法

 public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
}

5、主要执行过程
(1)执行set.add(“Tom”);

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
 	Node<K,V>[] tab; Node<K,V> p; int n, i;//创建一个putValue方法,输入hash(key)的int类型数据,key的String类型数据等数据
        if ((tab = table) == null || (n = tab.length) == 0)
        /*
         *1、为什么成员变量table为null?因为成员变量table默认值是null(transient Node<K,V>[] table);,且在之后的的所有构造方法中未给table赋值,因此table为null;
         *2、此前创建的全局变量table未赋值,因此为null( transient Node<K,V>[] table;),因此(tab = table) == null 成立,继续执行下一条语句;
         */
        	n = (tab = resize()).length;//resize()为创建一个重置数组的方法,首先使tab与table指向同一个地址,其次该地址上有一个数组resize(),因此tab表示该数组。该数组初始长度为16,tab=resize()使数组中每个元素都为null,n获取了该数组的长度,继续执行下一条语句;
        if ((p = tab[i = (n - 1) & hash]) == null)//此时hash即为"Tom","i = (n - 1) & hash"表示i为n-1按位与hash的随机的一个角标,由于tab中所有元素都为null,不可能和hash相同,因此(p = tab[i = (n - 1) & hash]) == null成立,继续执行下一条语句;
        	tab[i] = newNode(hash, key, value, null);//将数据存入tab[i]中,且由于tab和table指向一个地址,因此数据也存入到了table中;
//(中间不执行语句省略)
	if (++size > threshold)
            	resize();
        afterNodeInsertion(evict);
       	return null;
}

(2)执行set.add(“Tom”);

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
	Node<K,V>[] tab; Node<K,V> p; int n, i;//创建一个putValue方法,输入hash(key)的int类型数据,key的String类型数据等数据
        if ((tab = table) == null || (n = tab.length) == 0)//由于上一步执行过程中tab数组中存入了第一个"Tom"数据,则(tab = table)不为null,且(n = tab.length)必然不为零,所以if条件不成立,直接执行下一个if语句;
            	n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)//该条件中hash为第一个"Tom"存储的位置这个"i"与上一步执行过程的"i"相同,即tab[i]已经有了"Tom"数据,因此p= tab[i = (n - 1) & hash])不为null,执行else语句;
            	tab[i] = newNode(hash, key, value, null);
        else {
            	Node<K,V> e; K k;//创建Node对象
            	if (p.hash == hash &&
                	((k = p.key) == key || (key != null && key.equals(k))))//由于p.hash=tab[i]存储"Tom"数据,因此p.hash=hash;又因为p.key为String类型"Tom",与key相同,因此if条件成立,执行下一条语句;
               		e = p;
 //(中间不执行语句省略)
            	if (e != null) { // existing mapping for key //e不为null,执行下一条语句
                	V oldValue = e.value;
                	if (!onlyIfAbsent || oldValue == null)
                    		e.value = value;
                	afterNodeAccess(e);
                	return oldValue;//返回原值,即"Tom"数据
            	}
        }
        ++modCount;
        if (++size > threshold)
            	resize();
        afterNodeInsertion(evict);
        return null;
}

(3)执行set.add(“Lucy”);

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {//创建一个putValue方法,输入hash(key)的int类型数据,key的String类型数据等数据	
	Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)//由于此前执行过程中tab数组中存入了第一个"Tom"数据,则(tab = table)不为null,且(n = tab.length)必然不为零,所以if条件不成立,直接执行下一个if语句;
            	n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)//该hash中存储的int类型"Lucy"随机生成了在n-1中的一个i值,且由于该hash存储的数据与此前存储"Tom"数据的hash不同,因此该i与此前的i不同,该tab[i]为null,因此p = tab[i = (n - 1) & hash]为null,执行下一个语句;
		tab[i] = newNode(hash, key, value, null);//存入"Lucy"数据;
//(中间不执行语句省略)
        if(++size > threshold)
		resize();
        afterNodeInsertion(evict);
        return null;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值