Java集合(5)--Set接口及其实现类HashSet、LinkedHashSet和TreeSet

简介: Java集合(5)--Set接口及其实现类HashSet、LinkedHashSet和TreeSet

文章目录


Set接口概述

HashSet实现类

LinkedHashSet实现类

TreeSet实现类


Set接口概述


1、Set接口是Collection的子接口,set接口没有定义额外的方法,使用的都是Collection接口中的方法。

2、Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set 集合中,则添加操作失败。


6197325630d5493db2eed078be1e72d1.png


3、Set:存储无序的、不可重复的数据

(以HashSet为例说明)

①无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值。

②不可重复性:保证添加的元素按照equals()判断时,不能返回true。即:相同的元素只能添加一个。


HashSet实现类


1、HashSet 具有以下特点:

①不能保证元素的排列顺序

②HashSet 不是线程安全的

③集合元素可以是 null


2、HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。因此对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode()方法,以实现对象相等规则,即:“相等的对象必须具有相等的散列码”。


3、向HashSet中添加元素的过程:

我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(索引位置)。接着判断数组此位置上是否已经有元素:


如果此位置上没有其他元素,则元素a添加成功。—>情况1

如果此位置上有其他元素b(或以链表形式存在多个元素),则比较元素a与元素b的hash值:


如果hash值不相同,则元素a添加成功。—> 情况2

如果hash值相同,进而需要调用元素a所在类的equals()方法:


如果equals()返回true,元素a添加失败

如果equals()返回false,则元素a添加成功。—>情况3


对于添加成功的情况2和情况3而言:元素a与已经存在指定索引位置上数据以链表的方式存储。(七上八下)

jdk 7 : 新来元素a放到数组中,指向已存在的旧元素。

jdk 8 : 已存在的旧元素在数组中,指向新来元素a


f6bd270f624e4835b4ba08efc41358c8.png


底层为“数组+链表”,数组初始容量为16,当如果使用率超过0.75(16*0.75=12)就会扩大容量为原来的2倍。(16扩容为32,依次为64,128…等)


重写equals()方法的时候一般都需要同时复写hashCode()方法。通常参与计算hash值的对象的属性也应该参与到equals()中进行计算


381dbee0420f4c5abda31ad1c75b4da5.png


LinkedHashSet实现类


1、LinkedHashSet 是 HashSet 的子类,也是根据元素的 hashCode 值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的。


2、LinkedHashSet插入性能略低于 HashSet,但在迭代访问(遍历) Set 里的元素时有很好的性能。


3、LinkedHashSet 不允许集合元素重复。


760d14f105f941968dc5cf55c7c1bd88.png


TreeSet实现类


1、TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。元素应为相同类的对象。


2、TreeSet底层使用红黑树结构存储数据。


3、TreeSet 两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。


4、自然排序

①TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按条件排列。如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。实现 Comparable 的类必须重写compareTo(Object obj) 方法,两个对象通过compareTo(Object obj) 方法的返回值来比较大小。

②向 TreeSet 中添加元素时,只有第一个元素无须比较compareTo()方法,后面添

加的所有元素都会调用compareTo()方法进行比较。

③因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同

一个类的对象。

④对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是两个对象通过 compareTo(Object obj) 方法比较的返回值。


import java.util.Iterator;
import java.util.TreeSet;
/**
 * @Author: Yeman
 * @Date: 2021-09-16-16:48
 * @Description:
 */
class Student implements Comparable{
    String name;
    int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    //姓名从小到大,年龄从大到小排列
    public int compareTo(Object o) {
        if (o instanceof Student){
            Student student = (Student) o;
            int nameResult = this.name.compareTo(student.name);
            if (nameResult == 0){
                return -Integer.compare(this.age,student.age);
            }else {
                return nameResult;
            }
        }else throw new RuntimeException("类型不匹配");
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        treeSet.add(new Student("Tom",18));
        treeSet.add(new Student("Tom",22));
        treeSet.add(new Student("jim",18));
        treeSet.add(new Student("Anne",19));
        treeSet.add(new Student("Lily",25));
        treeSet.add(new Student("LiLei",25));
        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}


afe9246068fe4699843e3a3feedb34b9.png


5、定制排序

①定制排序,通过Comparator接口来实现,需要重写compare(T o1,T o2)方法。

②要实现定制排序,需要将实现Comparator接口的实例作为形参传递给TreeSet的构造器。

③仍然只能向TreeSet中添加类型相同的对象。否则发生ClassCastException异常。

④使用定制排序判断两个元素相等的标准是:通过Comparator比较两个元素返回了0。


import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/**
 * @Author: Yeman
 * @Date: 2021-09-16-16:48
 * @Description:
 */
class Student{
    String name;
    int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class TreeSetTest {
    public static void main(String[] args) {
        Comparator com = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Student && o2 instanceof Student) {
                    Student student1 = (Student) o1;
                    Student student2 = (Student) o2;
                    return Integer.compare(student1.age, student2.age);
                } else throw new RuntimeException("类型不匹配");
            }
        };
        TreeSet treeSet = new TreeSet(com);
        treeSet.add(new Student("Tom",18));
        treeSet.add(new Student("Tom",22));
        treeSet.add(new Student("jim",18));
        treeSet.add(new Student("Anne",19));
        treeSet.add(new Student("Lily",25));
        treeSet.add(new Student("LiLei",25));
        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}


24c08c87eb974e0ab4981e4f9f14c080.png




相关文章
|
2月前
|
机器学习/深度学习 人工智能 NoSQL
JAVA接入DeepSeek大模型接口开发---阿里云的百炼模型
随着大模型的越来越盛行,现在很多企业开始接入大模型的接口,今天我从java开发角度来写一个demo的示例,用于接入DeepSeek大模型,国内的大模型有很多的接入渠道,今天主要介绍下阿里云的百炼模型,因为这个模型是免费的,只要注册一个账户,就会免费送百万的token进行学习,今天就从一个简单的可以执行的示例开始进行介绍,希望可以分享给各位正在学习的同学们。
297 3
JAVA接入DeepSeek大模型接口开发---阿里云的百炼模型
|
1月前
|
Java 编译器 API
Java Lambda 表达式:以 Foo 接口为例深入解析
本文深入解析了 Java 8 中 Lambda 表达式的用法及其背后的函数式接口原理,以 `Foo` 接口为例,展示了如何通过简洁的 Lambda 表达式替代传统匿名类实现。文章从 Lambda 基本语法、函数式接口定义到实际应用层层递进,并探讨默认方法与静态方法的扩展性,最后总结常见误区与关键点,助你高效优化代码!
57 0
|
1月前
|
Java
java中一个接口A,以及一个实现它的类B,一个A类型的引用对象作为一个方法的参数,这个参数的类型可以是B的类型吗?
本文探讨了面向对象编程中接口与实现类的关系,以及里氏替换原则(LSP)的应用。通过示例代码展示了如何利用多态性将实现类的对象传递给接口类型的参数,满足LSP的要求。LSP确保子类能无缝替换父类或接口,不改变程序行为。接口定义了行为规范,实现类遵循此规范,从而保证了多态性和代码的可维护性。总结来说,接口与实现类的关系天然符合LSP,体现了多态性的核心思想。
39 0
|
3月前
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
582 5
|
2月前
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
81 2
|
3月前
|
编译器 容器
哈希表模拟封装unordered_map和unordered_set
哈希表模拟封装unordered_map和unordered_set
|
3月前
|
编译器 测试技术 计算机视觉
红黑树模拟封装map和set
红黑树模拟封装map和set
|
5月前
|
算法
你对Collection中Set、List、Map理解?
你对Collection中Set、List、Map理解?
119 18
你对Collection中Set、List、Map理解?
|
5月前
|
存储 缓存 安全
只会“有序无序”?面试官嫌弃的List、Set、Map回答!
小米,一位热衷于技术分享的程序员,通过与朋友小林的对话,详细解析了Java面试中常见的List、Set、Map三者之间的区别,不仅涵盖了它们的基本特性,还深入探讨了各自的实现原理及应用场景,帮助面试者更好地准备相关问题。
111 20
|
6月前
|
存储 C++ 容器
【C++】map、set基本用法
本文介绍了C++ STL中的`map`和`set`两种关联容器。`map`用于存储键值对,每个键唯一;而`set`存储唯一元素,不包含值。两者均基于红黑树实现,支持高效的查找、插入和删除操作。文中详细列举了它们的构造方法、迭代器、容量检查、元素修改等常用接口,并简要对比了`map`与`set`的主要差异。此外,还介绍了允许重复元素的`multiset`和`multimap`。
142 3
【C++】map、set基本用法

热门文章

最新文章