导读:

本篇是JAVA基础系列的第12篇,昨天我们梳理了集合中的List相关的知识点,今天我们接着梳理Set集合的相关知识点。

1.Set接口

java.util.Set 接口和 java.util.List 接口一样,同样继承自 Collection 接口,它与 Collection 接口中的方法基本一致,并没有对 Collection 接口进行功能上的扩充,只是比 Collection 接口更加严格了。与 List 接口不同的是, Set 接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。

2.List和Set的区别

List,Set都是继承自Collection接口。都是用来存储一组相同类型的元素的。

List特点:

  • 元素有放入顺序,元素可重复 。

  • 有顺序,即先放入的元素排在前面。

Set特点:

  • 元素无放入顺序,元素不可重复。

  • 无顺序,即先放入的元素不一定排在前面。不可重复,即相同元素在set中只会保留一份。所以,有些场景下,set可以用来去重。

3.Set如何保证元素不重复

在Java的Set体系中,根据实现方式不同主要分为两大类。HashSetTreeSet

  1. TreeSet 是二叉树实现的,Treeset中的数据是自动排好序的,不允许放入null值

  2. HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束

在HashSet中,基本的操作都是由HashMap底层实现的,因为HashSet底层是用HashMap存储数据的。当向HashSet中添加元素的时候,首先计算元素的hashcode值,然后通过扰动计算和按位与的方式计算出这个元素的存储位置,如果这个位置位空,就将元素添加进去;如果不为空,则用equals方法比较元素是否相等,相等就不添加,否则找一个空位添加。

TreeSet的底层是TreeMap的keySet(),而TreeMap是基于红黑树实现的,红黑树是一种平衡二叉查找树,它能保证任何一个节点的左右子树的高度差不会超过较矮的那棵的一倍。

TreeMap是按key排序的,元素在插入TreeSet时compareTo()方法要被调用,所以TreeSet中的元素要实现Comparable接口。TreeSet作为一种Set,它不允许出现重复元素。TreeSet是用compareTo()来判断重复元素的。

4.HashSet类

HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时就是使用这个实现类。HashSet 是按照 Hash 算法来存储集合中的元素。因此具有很好的存取和查找性能。

HashSet 具有以下特点:

  • 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化。

  • HashSet 不是同步的,如果多个线程同时访问或修改一个 HashSet,则必须通过代码来保证其同步。

  • 集合元素值可以是 null。

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据该 hashCode 值决定该对象在 HashSet 中的存储位置。如果有两个元素通过 equals() 方法比较返回的结果为 true,但它们的 hashCode 不相等,HashSet 将会把它们存储在不同的位置,依然可以添加成功。

也就是说,两个对象的 hashCode 值相等且通过 equals() 方法比较返回结果为 true,则 HashSet 集合认为两个元素相等

代码示例:

 public class SetDemo {public static void main(String[] args) {HashSet<String> nameSet = new HashSet<String>(); // 创建一个空的 Set 集合String name1 = "张三";String name2 = "李四";String name3 = "王五";String name4 = "钱六";nameSet.add(name1); // 将 name1 存储到 Set 集合中nameSet.add(name2); // 将 name2 存储到 Set 集合中nameSet.add(name3); // 将 name3 存储到 Set 集合中nameSet.add(name4); // 将 name4 存储到 Set 集合中nameSet.add(name4); // 重复添加name4,但是在集合中只能看到一个,因为Set集合不允许重复元素Iterator<String> it = nameSet.iterator();while (it.hasNext()) {System.out.println( it.next() ); // 输出 Set 集合中的元素}System.out.println("集合长度是:" + nameSet.size());}}

5.TreeSet类

TreeSet 类同时实现了 Set 接口和 SortedSet 接口。SortedSet 接口是 Set 接口的子接口,可以实现对集合进行自然排序,因此使用 TreeSet 类实现的 Set 接口默认情况下是自然排序的,这里的自然排序指的是升序排序。

TreeSet 只能对实现了 Comparable 接口的类对象进行排序,因为 Comparable 接口中有一个 compareTo(Object o) 方法用于比较两个对象的大小。例如 a.compareTo(b),如果 a 和 b 相等,则该方法返回 0;如果 a 大于 b,则该方法返回大于 0 的值;如果 a 小于 b,则该方法返回小于 0 的值。

TreeSet类的常用方法

方法名称 说明
E first() 返回此集合中的第一个元素。其中,E 表示集合中元素的数据类型
E last() 返回此集合中的最后一个元素
E poolFirst() 获取并移除此集合中的第一个元素
E poolLast() 获取并移除此集合中的最后一个元素
SortedSet<E> subSet(E fromElement,E toElement) 返回一个新的集合,新集合包含原集合中 fromElement 对象与 toElement 对象之间的所有对象。包含 fromElement 对象,不包含 toElement 对象
SortedSet<E> headSet<E toElement〉 返回一个新的集合,新集合包含原集合中 toElement 对象之前的所有对象。不包含 toElement 对象
SortedSet<E> tailSet(E fromElement) 返回一个新的集合,新集合包含原集合中 fromElement 对象之后的所有对 象。包含 fromElement 对象

注意:表面上看起来这些方法很多,其实很简单。因为 TreeSet 中的元素是有序的,所以增加了访问第一个、前一个、后一个、最后一个元素的方法,并提供了 3 个从 TreeSet 中截取子 TreeSet 的方法。

示例代码:

 public class TreeSetDemo {public static void main(String[] args) {TreeSet<Double> scores = new TreeSet<Double>(); // 创建 TreeSet 集合Scanner input = new Scanner(System.in);System.out.println("------------学生成绩管理系统-------------");for (int i = 0; i < 5; i++) {System.out.println("第" + (i + 1) + "个学生成绩:");double score = input.nextDouble();// 将学生成绩转换为Double类型,添加到TreeSet集合中scores.add(Double.valueOf(score));}Iterator<Double> it = scores.iterator(); // 创建 Iterator 对象System.out.println("学生成绩从低到高的排序为:");while (it.hasNext()) {System.out.print(it.next() + "\t");}System.out.println("\n请输入要查询的成绩:");double searchScore = input.nextDouble();if (scores.contains(searchScore)) {System.out.println("成绩为:" + searchScore + " 的学生存在!");} else {System.out.println("成绩为:" + searchScore + " 的学生不存在!");}// 查询不及格的学生成绩SortedSet<Double> score1 = scores.headSet(60.0);System.out.println("\n不及格的成绩有:");for (int i = 0; i < score1.toArray().length; i++) {System.out.print(score1.toArray()[i] + "\t");}// 查询90分以上的学生成绩SortedSet<Double> score2 = scores.tailSet(90.0);System.out.println("\n90 分以上的成绩有:");for (int i = 0; i < score2.toArray().length; i++) {System.out.print(score2.toArray()[i] + "\t");}}}

运行结果

 ------------学生成绩管理系统-------------第1个学生成绩:13第2个学生成绩:50第3个学生成绩:80第4个学生成绩:90第5个学生成绩:99学生成绩从低到高的排序为:13.050.080.090.099.0请输入要查询的成绩:50成绩为:50.0 的学生存在!不及格的成绩有:13.050.090 分以上的成绩有:90.099.0

6.HashSet实现原理

HashSet实现原理(基于源码总结)

  1. 基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。

  2. 当我们试图把某个类的对象当成 HashMap的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的equals(Object obj)方法和 hashCode() 方法,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。

  3. HashSet的其他操作都是基于HashMap的。

HashSet源码

 public class HashSet<E>extends AbstractSet<E>implements Set<E>, Cloneable, java.io.Serializable{static final long serialVersionUID = -5024744406713321676L;private transient HashMap<E,Object> map;// Dummy value to associate with an Object in the backing Mapprivate static final Object PRESENT = new Object();/*** Constructs a new, empty set; the backing <tt>HashMap</tt> instance has* default initial capacity (16) and load factor (0.75).*/public HashSet() {map = new HashMap<>();}//下方代码省略}

博观而约取,厚积而薄发!

java基础知识【第12期】-- 集合之Set相关推荐

  1. Java基础知识之什么是集合框架

    Java基础知识之什么是集合框架,前面的文章,我们已经学习了Java的一些基础知识,比如泛型.注解等等内容,接着本博客继续学习Java中一个很常见的内容,集合. 1.什么是Java中的集合框架? Ja ...

  2. Java基础知识 21(Set集合,HashSet集合以及它的三种遍历方式(迭代器,增强for循环,forEach),LinkedHashSet集合,TreeSet集合(自然排序法,比较器排序法))

    Java基础知识 21 Set集合 Set集合:一个不包含重复元素的Collection集合,元素不重复,List集合是允许元素重复的. Set接口的三个字类:HashSet(),LinkedHash ...

  3. Java基础知识融合(Arraylist集合,多态,继承,封装,包装类,循环嵌套,if嵌套等等)

    目录 1.项目大纲 1.项目前提 2.项目说明 3.项目内容 3.该软件完成以下功能: 2.软件设计 1.结构 2.类设计 3. 部分代码展示 心得: 1.项目大纲 1.项目前提 掌握java基本语法 ...

  4. Java基础知识(二)(Object类的常用方法、日期时间类、System类、StringBuilder类、包装类、Collection集合、Iterator迭代器、泛型、list集Set接口...)

    文章目录 Java基础知识(二) 1.Object类的常用方法 1.1 toString方法 1.2 equals方法 1.3 Objects类 2.日期时间类 2.1 Date类 2.2 DateF ...

  5. Java基础知识第二讲:Java开发手册/JVM/集合框架/异常体系/Java反射/语法知识/Java IO

    Java基础知识第二讲(Java编程规范/JVM/集合框架/异常体系/Java反射/语法知识/Java IO/码出高效) 分享在java学习及工作中,常使用的一些基础知识,本文从JVM出发,讲解了JV ...

  6. Java基础知识强化之集合框架笔记76:ConcurrentHashMap之 ConcurrentHashMap简介

    1. ConcurrentHashMap简介: ConcurrentHashMap是一个线程安全的Hash Table,它的主要功能是提供了一组和Hashtable功能相同但是线程安全的方法.Conc ...

  7. Java基础知识与集合部分面试题整理

    JAVA基础知识 一.JDK与JRE 1.JDK和JRE的区别 可从面向对象.主要作用和组成部分三方面对比.如下图所示: 2.JDK – Java Development Kit 1). 主要面向开发 ...

  8. 【剑指 Java】第 1 弹:靠这份 Java 基础知识总结,我拿到了满意的 Offer

    前言 因为博主是 2021 届毕业生,当时为了准备秋招,特意总结的 Java 基础知识面试高频题,最后也算找到了挺满意的工作.因此回馈给大家,希望能对大家起到一定的帮助. 0. 入门常识 0.1 Ja ...

  9. 学习java基础知识笔记

    Java基础知识 第一章.Java基础入门 1.JDK的组成 2.什么是注释,注释有哪些,字面量,什么是变量 注释是写在程序中对代码进行解释说明的文字,方便自己和其他人查看,以便理解程序的.单行注释. ...

  10. 【转】Java基础知识整理

    本博文内容参考相关博客以及<Java编程思想>整理而成,如有侵权,请联系博主. 转载请注明出处:http://www.cnblogs.com/BYRans/ PDF版下载链接:<Ja ...

最新文章

  1. 从Android中Activity之间的通信说开来
  2. 高级学员:2015年10月24日作业
  3. java长宽_Java:如何控制JPanel长宽比?
  4. Fiddler抓包使用教程-模拟低速网络环境
  5. 隐藏的iscroll元素显示后不能滚动问题
  6. 苹果“炸场”发布会官宣定档10月19日!终于等到你俩
  7. python计算蛋白质的质量
  8. 以太坊上已有十个DeFi协议的锁仓量超过10亿美元
  9. c语言指针选择排序1,求助利用指针进行选择排序
  10. centos7.0 安装vsftp实录
  11. python 文件和目录操作题库
  12. 为什么问多了,确实让人难以回答
  13. 《商务与经济统计》学习笔记(一)---数据与统计资料
  14. 用计算机怎么转换进制,计算机各种进制转换方法
  15. 美团2017校园招聘编程题
  16. 自学微信二次开发(1)
  17. 问菩萨为何倒坐,叹众生不肯回头
  18. java.sql.SQLException: Undefined Error
  19. 【linux】【docker】docker私服安装
  20. Java版吃豆游戏及源码

热门文章

  1. Windows常见垃圾清理方式
  2. Android面试之J2SE基础
  3. 全球各个国家及其首都中英文对照表
  4. 小米云测平台远程真机调试使用教程
  5. restTemplate接收image/jpeg格式
  6. Kettle Spoon字段拆分
  7. html如何取消页眉页脚设置,jquery web打印 取消 页眉和页脚
  8. 十月百度,阿里巴巴,迅雷搜狗最新面试五十三题(持续更新中10.16)
  9. java实现pdf导出
  10. win10计算机管理器在哪,Windows10如何打开资源管理器?Windows10任务管理器在哪?...