Set

介绍

1、无序、无索引
2、不允许重复,因此最多只能有一个null

HashSet

基本介绍

1、实现Set接口
2、本质上是HashMap:

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

3、可存null值,但最多只能有一个
4、无序,取决于hash之后,再确定索引的结果
5、不允许重复

add()底层

1、第一次添加时,table数组扩容到16,临界值(threshold)为16加载因子(loadFactor)0.75=12
2、如果table数组使用到了临界值12(>=),则会扩容到16
2=32,新的临界值为32*0.75=24,以此类推
3、HashMap中,(JDK8)如果一条链表的元素个数超过TREEIFY_THRSHOLD(默认为8),并且table的大小>=MIN_TREEIFY_CAPACITY(默认为64)就会进行树化(红黑树)

源码

public HashSet(){
	map=new HashMap();
}
public boolean add(E e){
	return map.put(e,PRESENT)=null;
	//				静态占位符
	//				(static) PRESENT =new Object();
}
//hash值并不是直接由hashCode()求出
public V put(K key,V value){
	return putVal(hash(key),key,value,false,true);
}
//hash(key)
static final int hash(Object key){
	int h;
	return (key==null)?0:(h=key.hashCode())^(h>>>16);
								//按位异或再右移16位
}
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=tabl.length)==0)//数组为null或长度为0
		n=(tab=resize()).length;//第一次扩容到16个空间
	/*
	(1)根据key,得到hash。计算该key应该存放到table表的哪个索引位置,
		并把这个对象赋值给p
	(2)判断p是否为null
	(2.1)如果为null,则表示无元素,就创建一个Node(key,value)
											   这里的value就是PRESENT
	(2.2)放在该位置tab[i]=newNode(hash,key,value,null)
	*/
	if(cp=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;
		/*
		  如果当前索引位置对应的链表的第一个元素和准备添加的key都hash值一样,
		  且引用相同或equals返回true,则不能加入
		*/
		else if(p instanceof TreeNode)
			e=((TreeNode<K,V>)p).putTreeVal(this,tab,hash,key,value);
		//判断p是否为一颗红黑树,如果是则调用putTreeVal添加
		else{
			//遍历比较若有相同则不能加入
			for(int binCount=0; ;++binCount){
				if((e=p.next)=null){
					p.next=newNode(hash,key,value,null);
					if(binCount>=TREEIFY_THRESHOLD-1)
						treeifyBin(tab,hash);
					/*
					添加元素之后,若链表长度达到8个,
					则对此链表树化(若表<64,则先扩容resize())
					*/
					break					
				}
				if(e.hash==hash)
					break;
				p=e;
			}
		}
	}
}

这里的源码解读我是学习韩老师的视频讲解: 韩顺平老师的讲解.

LinkedHashSet

基本介绍

1、HashSet的子类
2、底层为LinkedHashMap,维护了一个数组加双向链表
3、根据hashCode值来决定元素的存储位置,同时用链表维护元素的次序,这使元素看起来是以插入顺序保存的
4、不允许重复元素

底层

1、第一次添加时,直接将数组table扩容到16,存放的节点类型是LinkedHashMap $ Entry
2、数组为HashMap $ Node[]
//继承关系是在内部类中完成的

源码

static class Entry<K,V> extends HashMap.Node<K,V>{
	Entry<K,V> before,after;
	Entry(int hash,K key,V value,Node<K,V> next){
		super(hash,key,value,next);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值