【集合学习6】Set接口、HashSet、LinkedHashSet

Set接口和常用方法

Set接口基本介绍

在这里插入图片描述

Set接口常用方法和遍历方式

在这里插入图片描述
解读

  • 以Set接口的实现类HashSet讲解Set接口方法
  • set接口的实现类的对象,不能放重复元素,可以添加一个null
  • set接口对象存放的数据是无序的(添加和取出的顺序不一致)
  • 注意:取出的顺序是固定的

遍历

  • 可以使用迭代器
    在这里插入图片描述
  • 增强for
  • set接口对象不能通过索引来获取

Set接口实现类-HashSet

HashSet的说明

0

HashSet案例说明

  • 在执行add方法后,会返回一个boolean值,添加成功返回true,否则返回false
  • 可以通过remove指定删除某个对象
  • 对于对象来说,对象是否相同是根据equals方法判断的
  • 但是对于String来说是比较特别的
    在这里插入图片描述
  • 对于一些基础类型的包装类也是如此,画横线的意思,即使不写成包装类,在add的时候它也会以对象的方式存储,即包装成类
    在这里插入图片描述在这里插入图片描述

HashSet底层机质说明

在这里插入图片描述
在这里插入图片描述
源码解读

从构造器可以看出,HashSet的底层其实是HashMap
在这里插入图片描述
在这里插入图片描述
其中PRESENT是一个final static的空Object对象,占位用的在这里插入图片描述
putVal方法

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;//定义了辅助变量
        //这个table是HashMap中的一个属性,存放Node,类型为Node[]
        //if语句表示如果当前table是null,或者大小为0,就扩容,第一次为16
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        //1.根据key,得到hash 去计算该key应该存放到table表的哪个索引位置
        //并把这个位置的对象,赋值给p
        //2.判断p是否为null
        //2.1如果p为null,表示还没有存放元素,就创建一个Node(key="java",value=PRESENT)
        //2.2就放在该位置 tab[i]=newNode(hash,key,value,null)
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            //一个开发技巧,在需要局部变量(辅助变量)的时候,再创建
            Node<K,V> e; K k;
            
            //如果当前索引位置对应的链表的第一个元素和准备添加的key的hash值一样
            //并且满足下面两个条件之一:
			//(1)准备加入的key和 p指向的Node结点的key是同一个对象
			//(2) p 指向的Node结点的 key 的equals()和准备加入的key比较后相同		
			//就不能加入
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
                
            //再判断p是不是一颗红黑树,
			//如果是一颗红黑树,就调用putTreeVal ,来进行添加
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {//如果table对应索引位置,已经是一个链表,就使用for循环比较
				  //(1)依次和该链表的每一个元素比较后,都不相同,则加	入到该链表的最后
				  //注意在把元素添加到链表后,立即判断该链表是否已经达到8个结点
				  //,就调用treeifyBin() 对当前这个链表进行树化(转成红黑树)
				  //注意,在转成红黑树时,要进行判断,判断条件r
				  //if (tab == null || (n = tab.length)<MIN_TREEIFY_CAPACITY(64))
				  //    resize();
				  //如果上面条件成立,先table扩容。
				  //只有上面条件不成立时,才进行转成红黑树
				  //(2)依次和该链表的每一个元素比较过程中,如果有相同情况,就直接break

                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,TREEIFY_THRESHOLD=8,链表长度到达八个
                            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;
    }

数组默认大小为16,如果到达0.75倍就会扩容两倍

HashSet底层机质说明

在这里插入图片描述
说明

  • 如果想要把所有元素都放在一个链表上,要保证hashcode相同了,对于对象来说,可以重写hashcode方法来保证其相同。如果某个链表长度以及到达8,再向这个链表中添加元素,就会出发扩容机质,反复如此直到数组长度到达64,再添加就会变成树结构
  • 扩容,如果set内有8个元素,那么就扩容,不论这八个元素在哪

Set接口实现类-LinkedHashSet

LinkedHashSet继承了HashSet实现了Set接口
在这里插入图片描述
在这里插入图片描述
解读

  • LinkedHashSet加入顺序和取出元素顺序一致
  • LinkedHashSet底层维护的是一个LinkedHashMap(HashMap的子类)
  • LinkedHashSet底层结构(数组+双向链表)
  • 添加第一次时,直接将数组table扩容到16,存放的结点类型是 LinkedHashMap$Entry
  • 数组是 HashMap$Node[]存放的元素/数据是 LinkedHashMap$Entry类型
//继承关系是在内部类完成
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);
	}
}

源码分析

LinkedHashSet存放和取出的顺序一样,因为每一个节点都有两个指针指向前面和后面,在添加的时候指针会做出改变,但总体是一个环形的链表。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值