当前位置: 首页 > news >正文

【Java】泛型与集合篇 —— Set 接口

目录

  • Set 接口及实现类
    • HashSet 类
      • 特点
      • 内部实现
      • 构造方法
    • LinkedHashSet 类
      • 基本概念
      • 特点
      • 构造方法
      • 常用方法
      • 适用场景
    • 用 Set 对象实现集合运算
    • TreeSet 类
      • 特性
      • 构造方法
      • 常用方法
      • 注意事项
    • 对象顺序
      • 自然排序
      • 定制排序
      • 注意事项

Set 接口及实现类

HashSet 类

HashSet 是 Java 集合框架中 Set 接口的一个具体实现类,它存储唯一的元素,不允许重复值,且不保证元素的顺序。下面从多个方面详细介绍 HashSet 类。

特点

  1. 不允许重复元素:HashSet 会使用元素的 hashCode() 和 equals() 方法来确保元素的唯一性。当添加一个元素时,HashSet 首先会计算元素的哈希码,然后根据哈希码找到对应的存储位置,如果该位置已经有元素,会进一步使用 equals() 方法来判断两个元素是否相等,如果相等则不会添加该元素。
  2. 无序性:HashSet 不保证元素的存储顺序,即元素添加的顺序和遍历的顺序可能不同。
  3. 允许存储 null 元素:但只能存储一个 null 元素,因为重复的 null 元素会被视为相同元素而不被添加。
  4. 非线程安全:如果在多线程环境下使用,需要进行额外的同步处理,比如使用 Collections.synchronizedSet() 方法来包装 HashSet。

内部实现

HashSet 内部基于 HashMap 实现,它将元素存储在 HashMap 的键中,而值则统一使用一个静态的 PRESENT 对象。HashMap 的哈希表结构使得 HashSet 在插入、删除和查找元素时具有较好的性能,平均时间复杂度为 O (1)。

构造方法

  • HashSet() 创建一个空的散列集合,该集合的默认初始容量是 16,默认装填因子是 0.75。
  • HashSet(Collection c) 用指定的集合c的元素创建一个散列集合
  • HashSet(int initialCapacity) 创建一个散列集合,并指定集合的初始容量
  • HashSet(int initialCapacity,float loadFactor) 创建一个散列集合,并指定集合的初始容量和装填因子

以下是使用这些方法的代码示例:

import java.util.*;

public class HashSetExample {
   
    public static void main(String[] args) {
   
        // 使用HashSet()构造方法
        HashSet<Integer> hashSet1 = new HashSet<>();
        hashSet1.add(1);
        hashSet1.add(2);
        System.out.println("使用HashSet()构造的集合: " + hashSet1);

        // 使用HashSet(Collection c)构造方法
        List<Integer> list = new ArrayList<>();
        list.add(3);
        list.add(4);
        HashSet<Integer> hashSet2 = new HashSet<>(list);
        System.out.println("使用HashSet(Collection c)构造的集合: " + hashSet2);

        // 使用HashSet(int initialCapacity)构造方法
        HashSet<Integer> hashSet3 = new HashSet<>(10);
        hashSet3.add(5);
        hashSet3.add(6);
        System.out.println("使用HashSet(int initialCapacity)构造的集合: " + hashSet3);

        // 使用HashSet(int initialCapacity, float loadFactor)构造方法
        HashSet<Integer> hashSet4 = new HashSet<>(10, 0.8f);
        hashSet4.add(7);
        hashSet4.add(8);
        System.out.println("使用HashSet(int initialCapacity, float loadFactor)构造的集合: " + hashSet4);
    }
}

注意事项:

  1. 当使用自定义类作为 HashSet 的元素时,必须重写 hashCode() 和 equals() 方法,以确保元素的唯一性判断正确。
  2. 在多线程环境下使用时,要进行同步处理,否则可能会出现数据不一致的问题。

LinkedHashSet 类

LinkedHashSet 是 Java 集合框架中的一个类,它结合了 HashSet 的哈希表存储特性和链表维护插入顺序的特性。下面从基本概念、特点、常用方法、示例代码等方面对 LinkedHashSet 类进行详细介绍。

基本概念

LinkedHashSet 继承自 HashSet 并实现了 Set 接口。它内部使用哈希表(HashMap)来存储元素,同时使用双向链表维护元素的插入顺序。这意味着当你遍历 LinkedHashSet 时,元素会按照它们被插入的顺序返回。

特点

  1. 元素唯一:和其他 Set 实现类一样,LinkedHashSet 不允许存储重复的元素。当你尝试添加重复元素时,LinkedHashSet 会忽略该操作。
  2. 保持插入顺序:LinkedHashSet 会维护元素的插入顺序,当你遍历集合时,元素会按照它们被插入的顺序依次返回。
  3. 非线程安全:LinkedHashSet 不是线程安全的。如果多个线程同时访问一个 LinkedHashSet,并且至少有一个线程修改了该集合,那么它必须在外部进行同步。可以使用 Collections.synchronizedSet 方法来包装 LinkedHashSet 以实现线程安全。
  4. 性能:LinkedHashSet 的基本操作(如 add、remove 和 contains)的时间复杂度是 ,和 HashSet 相同。但是由于需要维护链表,它的空间开销会略大一些。

构造方法

  • LinkedHashSet():创建一个空的 LinkedHashSet,初始容量为 16,加载因子为 0.75。
  • LinkedHashSet(int initialCapacity):创建一个具有指定初始容量的空 LinkedHashSet,加载因子为 0.75。
  • LinkedHashSet(int initialCapacity, float loadFactor):创建一个具有指定初始容量和加载因子的空 LinkedHashSet。
  • LinkedHashSet(Collection<? extends E> c):创建一个包含指定集合中所有元素的 LinkedHashSet。

常用方法

LinkedHashSet 继承了 HashSet 的大部分方法,因为它是 HashSet 的子类。以下是一些常用方法:

  • 添加元素
    • boolean add(E e):将指定的元素添加到集合中,如果集合中已经包含该元素,则返回 false。
    • boolean addAll(Collection<? extends E> c):将指定集合中的所有元素添加到该集合中。
  • 删除元素
    • void clear():移除集合中的所有元素。
    • boolean remove(Object o):如果集合中包含指定的元素,则将其移除。
  • 查找元素
    • boolean contains(Object o):如果集合包含指定的元素,则返回 true。
  • 集合大小
    • int size():返回集合中的元素数量。
  • 遍历元素
    • 可以使用迭代器(Iterator)、增强 for 循环或 forEach 方法来遍历 LinkedHashSet 中的元素。

以下是使用这些方法的代码示例:

import java.util.LinkedHashSet;

public class LinkedHashSetExample {
   
    public static void main(String[] args) {
   
        // 创建一个 LinkedHashSet 并添加元素
        LinkedHashSet<String> fruits = new LinkedHashSet<>();
        fruits.add("Apple");
        fruits.add("Banana")

相关文章:

  • RT-Thread+STM32L475VET6实现红外遥控实验
  • 开题报告——基于Spring Boot的垃圾分类预约回收系统
  • 深度学习pytorch之19种优化算法(optimizer)解析
  • 【算法】动态规划专题⑦ —— 多重背包问题 + 二进制分解优化 python
  • umi react+antd 判断渲染消息提示、input搜索、多选按钮组
  • 【核心算法篇十二】《深入解剖DeepSeek多任务学习:共享表示层的24个设计细节与实战密码 》
  • 数组和指针常见笔试题(深度剖析)
  • Ubuntu:20.04更新cmake到更高版本
  • WebGPU 中的缓冲区输入速率:逐顶点与逐实例模式详解
  • FreeSwitch中mod_dptools和mod_easyroute两个模块及应用场景
  • DeepSeek VS ChatGPT-速度、准确性和成本
  • 使用GDI+、文件和目录和打印API,批量将图片按文件名分组打包成PDF
  • mysql兼容模式下smallint类型修改成boolean类型失败的处理办法
  • 使用 GPTQ 进行 4 位 LLM 量化
  • 校园网架构设计与部署实战
  • 一个网址,详细请求流程
  • leetcode150-逆波兰表达式求值
  • web入侵实战分析-常见web攻击类应急处置实验1
  • LeetCode:两两交换链表中的节点
  • 鸿蒙应用中使用本地存储实现数据共享
  • 从“重规模”向“重回报”转变,公募基金迎系统性改革
  • 公元1057年:千年龙虎榜到底有多厉害?
  • 应对美政策调整:中国重在开放与创新,维护好数据主权
  • 山东莒县农商银行去年收入、利润下降,资本充足率等指标增长
  • 线下无理由退货怎样操作?线上线下监管有何不同?市场监管总局回应
  • 何立峰将访问瑞士、法国并举行中美经贸高层会谈、第十次中法高级别经济财金对话