Java HashSet.add();方法底层代码

1.分析add()方法底层代码:

package add;

import java.util.HashSet;

public class Test {

	public static void main(String[] args) {
		HashSet<String> set = new HashSet<String>();    
		set.add("Tom");      //调用HashSet add方法,map.put(e, PRESENT),map为全局变量,map指向的是创建HashSet对象时创建的HashMap对象
		set.add("Tom");//思考:怎么判断不允许重复?
HashSet<String> set = new HashSet<String>();  

创建HashSet对象,调用了该类中无参构造方法,执行了该构造方法中map = new HashMap<>();,map为HashSet全局变量,蓝色大写的是常量.
在这里插入图片描述
map为一个全局变量。
在这里插入图片描述
首先分析hashCode();

package add;

import java.util.HashSet;

public class Test {

	public static void main(String[] args) {
		Test test = new Test();
		System.out.println(test.hashCode());      //输出对应于对象的某一个数
		System.out.println(test);                         //默认调用toString方法
		System.out.println(test.toString());        //输出对象的地址
        }
    }	

在这里插入图片描述

package add;

import java.util.HashSet;

public class Test {

	public static void main(String[] args) {
		String name1 = "tom";
		String name2 = "tom";
		System.out.println(name1.hashCode()); 
		System.out.println(name2.hashCode());
		}
	}

在这里插入图片描述
但是如果创建对象了,就是不同的结果。

package add;

import java.util.HashSet;

public class Test {

public static void main(String[] args) {
		Test test = new Test();
		Test test1 = new Test();
		System.out.println(test.hashCode());      
		System.out.println(test1.hashCode()); 
		}
    }

在这里插入图片描述

package add;

import java.util.HashSet;

public class Test {

public static void main(String[] args) {
		Test test = new Test();
		System.out.println(test.hashCode());     
		test = new Test();  //新建一个对象赋值给test,所以俩次结果是不一样的
		System.out.println(test1.hashCode()); 
		}
    }

结论:不同对象的hashCode一定不相同;相同对象的HashCode的值一定相同,所以HashMap中hash方法:传入相同的对象,得到相同的结果。

2.以第一个代码块分析add()底层代码:

 public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
 public V put(K key, V value) {
	        return putVal(hash(key), key, value, false, true);
	     }
 static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

这时的key就是:“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;
	        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;
	            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;
	     }

第一次添加“tom”; if ((tab = table) == null || (n = tab.length) == 0)table是全局变量,并没有给全局变量赋值,
在这里插入图片描述
所以table=null。
n = (tab = resize()).length; resize() 返回一个数组,在其中给全局变量table赋值,就是与table指向同一个地址 ,而且方法返回newtab,赋值给tab,所以table与tab也指向同一个地址
if ((p = tab[i = (n - 1) & hash]) == null) n=16
tab[i] = newNode(hash, key, value, null);添加第一个Tom tab[i],tab与table指向同一个地址,所以table[i]也是有值的,且相同。
在第二次添加“tom”;时,

 if ((tab = table) == null || (n = tab.length) == 0)
	            n = (tab = resize()).length;        

因为table是全局变量,第一次添加"tom";已经有值了,所以第二次的时候不是空,因为这俩行代码就不再执行了

根据if ((p = tab[i = (n - 1) & hash]) == null)执行else
在else中执行代码:

 if (p.hash == hash &&
	                ((k = p.key) == key || (key != null && key.equals(k))))
	                e = p;

最后,因为

				 if (e != null) {                     
	                V oldValue = e.value;
	                if (!onlyIfAbsent || oldValue == null)
	                    e.value = value;           
	                afterNodeAccess(e);
	                return oldValue;
	            }

e中有第二次传过来的对象,所以将这次value的值覆盖前一次的值,最后返回方法。所以这一次,就没有添加成功。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值