Java:Set接口小记

对 Java 中的 Set接口 与 其实现类,做一个微不足道的小小小小记

概述

public interface Set<E> extends Collection<E> {
// ...
}

Set 接口继承了 Collection 接口,Set集合中不能包含重复的元素,每个元素必须是唯一的,你只要将元素加入 Set 中,重复的元素会自动移除。

对于 Set 的个人理解:

  1. 使用上:就是不能带有重复元素的 List;
  2. 本质上:只用了 key 的 Map,一个串了马甲的 Map

HashSet

概述

披着马甲的 HashMap:Java:HashMap类小记

public HashSet() {
map = new HashMap<>();
}
  1. HashSet 中不能有相同的元素,但可以有 null 元素,即元素具有唯一性;

    其底层采用的还是 HashMap,对于 put 元素,其采用的方式为:

    // HashSet的底层为一个HashMao结构
    private transient HashMap<E, Object> map;
    // 作为一个占位符
    // private static final Object PRESENT = new Object(); public HashSet() {
    map = new HashMap<>();
    }
    public boolean add(E e) {
    return map.put(e, PRESENT)==null;
    }

    从上述 add 方法可知:HashSet 保证元素不重复的方式

    元素值作为的是 map 的 key,map 的 value 则是 PRESENT 变量,这个变量只作为放入 map 时的一个占位符而存在,所以没什么实际用处。其实,这时候答案已经出来了:HashMap 的 key 是不能重复的,而这里HashSet 的元素又是作为了 map 的 key,当然也不能重复了。

    LinkedHashSet、TreeSet 都一样,都采用了 PRESENT 这个占位符。

  2. 存入 HashSet 的元素是无序的;

  3. 添加、删除元素的操作时间复杂度都为O(1);

  4. 非线程安全。

实现原理

  1. HashSet 的实现是依赖于 HashMap 的,HashSet 的值都是存储在 HashMap 中的;

    public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable{}
  2. 在 HashSet 的构造法中会初始化一个 HashMap 对象,HashSet 的值是作为 HashMap 的 key 存储在 HashMap 中的,当存储的值已经存在时返回 false;

    private transient HashMap<E,Object> map;
    public HashSet() {
    map = new HashMap<>();
    }
    public boolean add(E e) {
    return map.put(e, PRESENT)==null;
    // private static final Object PRESENT = new Object();
    }
  3. HashSet 的其他操作都是基于 HashMap 的

    public int size() {
    return map.size();
    }
    public boolean isEmpty() {
    return map.isEmpty();
    }
    public boolean add(E e) {
    return map.put(e, PRESENT)==null;
    }
    public boolean remove(Object o) {
    return map.remove(o)==PRESENT;
    }
    // ....

LinkedHashSet

概述

披着马甲的 LinkedHashMap:Java:LinkedHashMap类小记

public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable { public LinkedHashSet(int initialCapacity, float loadFactor) {
// super:用了HashSet中的构造函数,且第三个参数为true
// 其他的构造函数也相同,第三个元素都为true
super(initialCapacity, loadFactor, true);
}
} // 进入HashSet查看对应的构造函数
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
// 这里new了一个LinkedHashMap
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
  1. LinkedHashSet 中不能有相同元素,可以有一个 null 元素,元素严格按照放入的顺序排列;
  2. 添加、删除元素的操作时间复杂度都为O(1);
  3. 非线程安全。

实现原理

  1. 对于 LinkedHashSet 而言,它继承于 HashSet、又基于 LinkedHashMap 来实现的;

    public class LinkedHashSet<E>
    extends HashSet<E> // 继承了hashset
    implements Set<E>, Cloneable, java.io.Serializable { public LinkedHashSet(int initialCapacity, float loadFactor) {
    super(initialCapacity, loadFactor, true);
    } public LinkedHashSet(int initialCapacity) {
    super(initialCapacity, .75f, true);
    } public LinkedHashSet() {
    super(16, .75f, true);
    }
    }
  2. LinkedHashSet 底层使用 LinkedHashMap 来保存所有元素,它继承于 HashSet,其所有的方法操作上又与 HashSet 相同;

TreeSet

概述

披着马甲的 TreeSet:Java:TreeMap类小记

public TreeSet() {
this(new TreeMap<E,Object>());
}
  1. TreeSet 是中不能有相同元素,不可以有null元素,根据元素的自然顺序进行排序;
  2. 添加、删除操作时间复杂度都是O(log(n));
  3. 非线程安全

实现原理

  1. TreeSet 底层实际使用的存储容器就是 TreeMap;

    public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable
    {
    private transient NavigableMap<E,Object> m; public TreeSet() {
    // 底层实际使用的存储容器就是 TreeMap;
    this(new TreeMap<E,Object>()); // 调用 TreeSet
    } // 把TreeMap赋值给了NavigableMap<E,Object>
    TreeSet(NavigableMap<E,Object> m) {
    this.m = m;
    } public boolean add(E e) {
    // 本质上还是调用了 TreeMap 的方法
    return m.put(e, PRESENT)==null;
    }
    }
  2. TreeSet 里绝大部分方法都是直接调用 TreeMap 的方法来实现的;

总结

首先,Set 集合不包含重复元素,都具有唯一性;

当无排序要求可以选用 HashSet;

若想取出元素的顺序和放入元素的顺序相同,那么可以选用 LinkedHashSet;

若想插入、删除立即排序或者按照一定规则排序可以选用 TreeSet。

参考

https://blog.csdn.net/StemQ/article/details/66477615

https://mp.weixin.qq.com/s/q1r9Pno6ANUzZ9wMzA-JSg

https://blog.csdn.net/qq_41026809/article/details/90449073

https://www.cnblogs.com/baojun/p/11087004.html

https://blog.csdn.net/jtcode_is_my_partner/article/details/81408392

Java:Set接口小记的更多相关文章

  1. Java:抽象类和接口小记

    Java:抽象类和接口小记 对 Java 中的 抽象类和接口,做一个微不足道的小小小小记 抽象类:使用 abstract 修饰,子类用 extends 继承: 接口:使用 interface 修饰,采 ...

  2. Java:AQS 小记-2(ReentrantLock)

    Java:AQS 小记-2(ReentrantLock) 整体结构 ReentrantLock 类图 AbstractOwnableSynchronizer 类 public abstract cla ...

  3. Java:ThreadLocal小记

    Java:ThreadLocal小记 说明:这是看了 bilibili 上 黑马程序员 的课程 java基础教程由浅入深全面解析threadlocal 后做的笔记 内容 ThreadLocal 介绍 ...

  4. Java:内部类小记

    Java:内部类小记 对 Java 中的 内部类,做一个微不足道的小小小小记 首先:内部类是指在一个外部类的内部再定义一个类.内部类作为外部类的一个成员,并且依附于外部类而存在的. 成员内部类 成员内 ...

  5. Java:异常小记

    Java:异常小记 对 Java 中的 异常 ,做一个微不足道的小小小小记 Error 和 Exception 相同点: Exception 和Error 都是继承了 Throwable 类,在 Ja ...

  6. Java:创建对象小记

    Java:创建对象小记 对 Java 中的创建对象的内容,做一个微不足道的小小小小记 创建对象的方式概述 使用 new 关键字:Person person = new Person(); 反射创建:使 ...

  7. 深入理解Java的接口和抽象类(转)

    深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...

  8. 深入理解Java的接口和抽象类

    深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...

  9. java微信接口之五—消息分组群发

    一.微信消息分组群发接口简介 1.请求:该请求是使用post提交地址为: https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_t ...

随机推荐

  1. Java基础之类加载器

    Java类加载器是用户程序和JVM虚拟机之间的桥梁,在Java程序中起了至关重要的作用,理解它有利于我们写出更优雅的程序.本文首先介绍了Java虚拟机加载程序的过程,简述了Java类加载器的加载方式( ...

  2. QT之ARM平台的移植

      在开发板中运行QT程序的基本条件是具备QT环境,那么QT的移植尤为重要,接下载我将和小伙伴们一起学习QT的移植. 一.准备材料 tslib源码 qt-everywhere-src-5.12.9.t ...

  3. Nginx:常用基本命令与异常处理

    Nginx日志 - ./nginx-1.6.0-ems/logs/nginx.pid Nginx启动时应该使用cmd等命令行工具启动,双击启动同样会产生进程但会造成异常,判断条件是 ./nginx-1 ...

  4. 忘记root密码的情况下如何给指定账户开通远程访问

    1.跳过验证使用root登录 net stop mysql //停止MYSQL服务 打开第一个cmd窗口,切换到mysql的bin目录,运行命令: mysqld --defaults-file=&qu ...

  5. 集合Collection ----List集合

    Collection集合体系的特点: set系列集合:添加的元素是 无序,不重复,无索引的 ----HashSet: 无序,不重复,无索引 ----LinkedHashSet: 有序,不重复,无索引 ...

  6. CodeForce-803B Distances to Zero(贪心DP)

    Distances to Zero CodeForces - 803B 题意:给定一个数列 a0, a1, ..., an - 1.对于数列中的每一项都要求出与该项最近的0与该项的距离.保证数列中有至 ...

  7. Rust之旅 02.通过例子学习自定义类型

    本期文章接上期继续讲述Rust语言中的数据类型,Rust自定义数据类型主要是通过下面这两个关键字来创建: 结构体( struct ): 定义一个结构体(structure) 枚举( enum ): 定 ...

  8. Jmeter扩展组件开发(6) - 将响应结果数据显示到查看结果树中

    CODE //用来存储响应数据,目的是将响应结果放到查看结果树当中private String resultData;/** 这个方法就是实现你具体功能逻辑的方法* @param javaSample ...

  9. Jmeter系列(6)- 分析源码,创建登录、浏览商品接口请求

    前言简介 接口的压力测试有个二八原则:线上80%的用户量在一天24小时20%(即4.8个小时)的时间里可以平稳运行,这个接口就算是通过压力测试了 源码分析 登录 浏览商品 创建请求 登录 浏览菜单 C ...

  10. 一文让你彻底理解SELECT语句的执行逻辑

    正常情况下SELECT的书写顺序和执行顺序: 书写顺序: SELECT>FROM >WHERE>GROUP BY>HAVE>ORDER BY 执行顺序: FROM > ...