浅谈Java的LinkedHashSet源码

 更新时间:2023年09月05日 10:50:59   作者:小成同学_  
这篇文章主要介绍了浅谈Java的LinkedHashSet源码,底层是链表实现的,是set集合中唯一一个能保证怎么存就怎么取的集合对象
因为是HashSet的子类,所以也是保证元素唯一的,与HashSet的原理一样,需要的朋友可以参考下

LinkedHashSet

问题

(1)LinkedHashSet 的底层使用什么存储元素?

(2)LinkedHashSet 与 HashSet 有什么不同?

(3)LinkedHashSet 是有序的吗?

(4)LinkedHashSet 支持按元素访问顺序排序吗?

LinkedHashSet的概述和使用

A:LinkedHashSet的特点

LinkedHashSet

底层是链表实现的,是set集合中唯一一个能保证怎么存就怎么取的集合对象

因为是HashSet的子类,所以也是保证元素唯一的,与HashSet的原理一样

B:案例演示

LinkedHashSet的特点

可以保证怎么存就怎么取

package com.heima.set;
import java.util.LinkedHashSet;
public class Demo02_LinkedHashSet {
	public static void main(String[] args) {
		LinkedHashSet<String> lhs = new LinkedHashSet<>();
		lhs.add("a");
		lhs.add("a");
		lhs.add("a");
		lhs.add("a");
		lhs.add("b");
		lhs.add("c");
		lhs.add("d");
		System.out.println(lhs);
	}
}

上一节我们说 HashSet 中的元素是无序的,那么有没有什么办法保证 Set 中的元素是有序的呢?

答案是当然可以。

我们今天的主角 LinkedHashSet 就有这个功能,它是怎么实现有序的呢?让我们来一起学习吧。

如果你已看过前面关于 HashSet 和 HashMap,一定能够想到本文将要讲解的 LinkedHashSet 和 LinkedHashMap 其实也是一回事,前者仅仅是对后者做了一层包装,也就是说 LinkedHashSet 里面有一个 LinkedHashMap(适配器模式)

LinkedHashSet 的本质就是 LinkedHashMap。

继承体系

image-20221203211217024

源码解析

LinkedHashSet 继承了 HashSet,其增删改查等方法使用的都是 HashSet 的方法,我们直接看它的全部源码。

package java.util;
// LinkedHashSet继承自HashSet
public class LinkedHashSet<E>
    extends HashSet<E>
    implements Set<E>, Cloneable, java.io.Serializable {
    private static final long serialVersionUID = -2851667679971038690L;
    // 传入容量和装载因子
    public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }
    // 只传入容量,装载因子默认为0.75
    public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);
    }
    // 使用默认容量16,默认装载因子0.75
    public LinkedHashSet() {
        super(16, .75f, true);
    }
    // 将集合c中的所有元素添加到LinkedHashSet中
    // 好奇怪,这里计算容量的方式又变了
    // HashSet中使用的是Math.max((int) (c.size()/.75f) + 1, 16)
    // 这一点有点不得其解,是作者偷懒?
    public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }
    // 可分割的迭代器,主要用于多线程并行迭代处理时使用
    @Override
    public Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
    }
}

完了,结束了,就这么多,这是全部源码了,真的。

可以看到,LinkedHashSet 中一共提供了 5 个方法,其中 4 个是构造方法,还有一个是迭代器。

4 个构造方法都是调用父类的 super(initialCapacity, loadFactor, true); 这个方法。

这个方法长什么样呢?

还记得我们上一节说过一个不是 public 的构造方法吗?就是它。

    // HashSet的构造方法
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
					   ||
				  	   \/
	// 上面的构造器调用的是LinkedHashMap的这个构造器,其accessOrder是固定的为false,即不能实现LRU,链表只能按照元素的添加顺序进行排序。
    public LinkedHashMap(int initialCapacity, float loadFactor) {
        // 再调用HashMap的构造器
        super(initialCapacity, loadFactor);
        // accessOrder固定为false,不能为其赋值,即不支持LRU。
        accessOrder = false;
    }

如上所示,这个构造方法里面使用了 LinkedHashMap 来初始化 HashSet 中的 map。

现在这个逻辑应该很清晰了,LinkedHashSet 继承自 HashSet,它的添加、删除、查询等方法都是直接用的 HashSet 的,唯一的不同就是它使用 LinkedHashMap 存储元素。

上一篇我们学习了 LinkedHashMap,此时我们会想到一个问题,既然 LinkedHashSet 是基于 LinkedHashMap 实现的,那它可以实现 LRU 吗?

答案是 不可以

因为我们看到,LinkedHashSet 所有的构造方法都是调用 HashSet 的同一个构造方法,而 HashSet 中初始化 map 的构造方法,默认把 accessOrder 设置为 false 了。

所以,LinkedHashSet 是不支持按访问顺序对元素排序的,无法实现 LRU,只能按插入顺序排序。

那么,开篇那几个问题是否能回答了呢?

总结

(1)LinkedHashSet 的底层使用 LinkedHashMap 存储元素。

(2)LinkedHashSet 是有序的,它是按照插入的顺序排序的 (不支持 LRU)

到此这篇关于浅谈Java的LinkedHashSet源码的文章就介绍到这了,更多相关Java的LinkedHashSet内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • linux配置jdk环境变量简单教程

    linux配置jdk环境变量简单教程

    这篇文章主要为大家详细介绍了linux配置jdk环境变量简单教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • Java利用TCP实现服务端向客户端消息群发的示例代码

    Java利用TCP实现服务端向客户端消息群发的示例代码

    这篇文章主要为大家详细介绍了Java如何利用TCP协议实现服务端向客户端消息群发功能,文中的示例代码讲解详细,需要的可以参考下,希望对你有所帮助
    2022-08-08
  • SpringBoot @Configuration与@Bean注解使用介绍

    SpringBoot @Configuration与@Bean注解使用介绍

    这篇文章主要介绍了SpringBoot中的@Configuration与@Bean注解,在进行项目编写前,我们还需要知道一个东西,就是SpringBoot对我们的SpringMVC还做了哪些配置,包括如何扩展,如何定制,只有把这些都搞清楚了,我们在之后使用才会更加得心应手
    2022-10-10
  • jar包打包成exe安装包的实现

    jar包打包成exe安装包的实现

    本文主要介绍了jar包打包成exe安装包的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • SpringBoot集成WebSocket实现前后端消息互传的方法

    SpringBoot集成WebSocket实现前后端消息互传的方法

    这篇文章主要介绍了SpringBoot集成WebSocket实现前后端消息互传的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • java实现根据ip地址获取地理位置

    java实现根据ip地址获取地理位置

    本文给大家汇总介绍了2种分别使用新浪和淘宝接口,实现根据IP地址获取详细的地理位置的代码,非常的实用,有需要的小伙伴可以参考下。
    2016-03-03
  • Spring Boot中@value的常见用法及案例

    Spring Boot中@value的常见用法及案例

    @Value注解是Spring框架中强大且常用的注解之一,本文主要介绍了SpringBoot中@value的常见用法及案例,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • springmvc 防止表单重复提交的两种方法

    springmvc 防止表单重复提交的两种方法

    最近在本地开发测试的时候,遇到一个表单重复提交的现象。本文主要介绍了springmvc 防止表单重复提交的两种方法,感兴趣的可以了解一下
    2021-08-08
  • Java中常用的代码汇总

    Java中常用的代码汇总

    本文给大家分享了20个常用的java代码,都是别人项目中使用过的代码,这里推荐给大家,有需要的小伙伴可以参考下。
    2015-05-05
  • Java日期处理工具类DateUtils详解

    Java日期处理工具类DateUtils详解

    这篇文章主要为大家详细介绍了Java日期处理工具类DateUtils的相关代码,包含日期和时间常用操作,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12

最新评论