zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【JAVA】LinkedHashSet集合的概念及其与LinkedHashMap有序的原因

JAVA概念集合 及其 原因 有序 LinkedHashMap
2023-09-11 14:20:37 时间

LinkedHashSet集合特点

LinkedHashSet是Set集合的一个实现,具有set集合不重复的特点,同时具有可预测的迭代顺序,也就是我们插入的顺序。并且linkedHashSet是一个非线程安全的集合。如果有多个线程同时访问当前linkedhashset集合容器,并且有一个线程对当前容器中的元素做了修改,那么必须要在外部实现同步保证数据的冥等性

冥等性的理解:http://www.smithfox.com/?e=16 

 

LinkedHashSet集合的源码实现

我们new一个LinkedHashSet看一下具体的源码实现。

LinkedHashSet<List> l = new LinkedHashSet<>();

注:这里我们实际创建的是一个LinkedHashMap带有制定大小和加载因子的容器

深入理解java中的容器:https://blog.csdn.net/a2011480169/article/details/52047600

​
/**
     * ...
     */
    public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }

    /**
     * ...
     */
    public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);
    }

    /**
     * ...
     */
    public LinkedHashSet() {
        super(16, .75f, true);
    }

    /**
     * ...
     */
    public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }

​

 

LinkedHashSet集合的实质

LinkedHashSet实际上是一个哈希表和链表的结合,且是一个双向链表

双向链表是链表的一种,他的每个数据节点都有两个指针分别指向直接后继直接前驱所以从双向链表的任意一个节点开始都可以很方便的访问它的前驱节点和后继节点。这是双向链表的优点,那么有优点就有缺点,缺点是每个节点都需要保存当前节点的next和prev两个属性,这样才能保证优点。所以需要更多的内存开销,并且删除和添加也会比较费时间。

 

插入顺序的保证

那是LinkedHashSet集合是如何保证数据插入顺序的?

java单向和双向链表详解:https://blog.csdn.net/Sun_Ru/article/details/51784058

在新创建的LinkedHashSet的对象的下面,对元素进行添加。我们走进去看一下add();方法

跟进来走的是put的方法:LinkedHashSet.class下的,这个是重写了父类(超类)中put的具体add方法。他会在新分配的元素在链表的末尾插入一条。

进来走的还是HashMap的put添加方法,在上面的判断和计算hash确定位置之后,由于LinkedHashSet重写了addEntry

在元素的后面添加新的元素。

整个过程就是LinkedHashSet在容器插入数据的过程。此过程主要由LinkedHashSet.class中重写超类的两个addEntry和createEntry 实现双向链表的结构。保证数据已我们录入的顺序遍历输出。

 

注:IntelliJ IDEA中 查看某个类中的所有方法的组合键:

https://blog.csdn.net/tb9125256/article/details/81416358

https://blog.csdn.net/qq_27093465/article/details/50853429

LinkedHashSet集合与LinkedHashMap有序的原因

哈希表是无序的

因为往进去存的元素都是随机存的。而它之所以有序的原因是,往里头存的元素多了一个指针。

我们一般往哈希表里存的是KeyValue,而只要带哈希的,我们往里头存的,就有KeyValuenext的指针。

所以,我们存的时候随便存,但是指针是按顺序把每个元素连起来的。

比如说,我们可以将元素存到数组里头,而他的地址我们可以通过next指针,用链表按顺序将其连起来。

也就是说,在数组里我们随便存元素的值。可是该元素的地址,我们将其存给第一个元素。

在迭代的时候其实就是用链表在迭代,即存的时候用哈希存,因为速度快。访问的时候用链表访问,为的是有序