Java集合大总结——Collection集合

2023-11-04

1、List,Set,Queue,Map四者的区别

在这里插入图片描述

Java 集合, 也叫作容器,主要是由两大接口派生而来:一个是 Collection 接口,主要用于存放单一元素;另一个是 Map 接口,主要用于存放键值对。对于Collection 接口,下面又有三个主要的子接口: List 、 Set 和 Queue
在这里插入图片描述

集合底层数据结构梳理

  • List, Set, Queue, Map四者都是Collection 接口的子接口,都可以使用for-each 循环语法遍历元素,其它的区别见图上所示。
  • 关于四者的实现类之间的区别
  • List接口
    • ArrayList:Object[]数组
    • Vector:Object[]数组
    • LinkedList:双向链表
  • Set接口
    • HashSet(无序,唯一):底层使用HashMap存储数据
    • LinkedHashSet:LinkedHashSet 是 HashSet 的子类,并且其内部是通过 LinkedHashMap 来实现的。
    • TreeSet (有序,唯一): 红黑树(自平衡的排序二叉树)
  • Queue接口
    • Deque接口:双端队列
    • PriorityQueue : Object[] 数组
    • ArrayDeque : Object[] 数组
  • Map接口
    • HashMap:数组 + 链表|红黑树。
      • 添加元素时,如果当前数组的长度小于 64,那么会选择先进行数组扩容。
      • 如果数组长度达到64时,数组不在扩容,而是转换数组 + 链表存储元素。
      • 当链表长度大于阈值(默认为 8)时,将链表转化为红黑树,以减少搜索时间。
    • LinkedHashMap:(双向链表) +(数组 + 链表|红黑树),其中的双向链表实现了LinkedHashMap 能顺序访问。
    • Hashtable :数组+链表组成的
    • TreeMap :红黑树(自平衡的排序二叉树)
      注意:关于HashMap 和 Hashtable 的区别还需要详细介绍。

2、关于集合的的选用

我们主要根据集合的特点来选择合适的集合。比如:

  • 需要根据键值获取到元素值时就选用 Map 接口下的集合
    • 需要排序时选择 TreeMap
    • 不需要排序时就选择 HashMap
    • 需要保证线程安全就选用 ConcurrentHashMap
  • 只需要存放元素值时,就选择实现 Collection 接口的集合
    • 需要保证元素唯一时选择实现 Set 接口的集合比如 TreeSet 或 HashSet
    • 不需要保证元素唯一时选择实现 List 接口的集合比如 ArrayList 或 LinkedList
  • 需要队列时就选择Queue接口下的集合
  • 单端队列就选择PriorityQueue
  • 双端队列就选ArrayDeque

2.1 为什么使用集合

  • 当我们需要存储一组类型相同的数据时,数组是最常用且最基本的容器之一。但是,使用数组存储对象存在一些不足之处,因为在实际开发中,存储的数据类型多种多样且数量不确定。这时,Java 集合就派上用场了。
  • 与数组相比,Java 集合提供了更灵活、更有效的方法来存储多个数据对象。Java集合框架中的各种集合类和接口可以存储不同类型和数量的对象,同时还具有多样化的操作方式。相较于数组,Java 集合的优势在于它们的大小可变、支持泛型、具有内建算法等。
  • 总的来说,Java 集合提高了数据的存储和处理灵活性,可以更好地适应现代软件开发中多样化的数据需求,并支持高质量的代码编写

3、List接口

List集合的特点

3.1 ArrayList 和 Array(数组)的区别?

ArrayList 内部基于动态数组实现,比 Array (静态数组) 使用起来更加灵活:

  • ArrayList 会根据实际存储的元素动态地扩容或缩容,而 Array 被创建之后就不能改变它的长度了。
  • ArrayList 允许你使用泛型来确保类型安全, Array 则不可以。
  • ArrayList 中只能存储对象。对于基本类型数据,需要使用其对应的包装类(如 Integer、Double 等,不能是int,double等)。 Array 可以直接存储基本类型数据,也可以存储对象。
  • ArrayList 支持插入、删除、遍历等常见操作,并且提供了丰富的 API 操作方法,比如 add() 、 remove() 等。 Array 只是一个固定长度的数组,只能按照下标访问其中的元素,不具备动态添加、删除元素的能力。
  • ArrayList 创建时不需要指定大小,而 Array 创建时必须指定大小。

3.1 LinkedList 为什么不能实现RandomAccess 接口?

RandomAccess 是一个标记接口,用来表明实现该接口的类支持随机访问(即可以通过索引快速访问元素)。由于 LinkedList 底层数据结构是链表,内存地址不连续,只能通过指针移动来定位,不支持随机快速访问,所以不能实现RandomAccess 接口。

4.ArrayList 与 LinkedList 区别?

LinkedList类:

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

在这里插入图片描述
ArrayList集合类:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

在这里插入图片描述

根据以上的继承结构图理解:

  • 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
  • 底层数据结构: ArrayList 底层使用的是 Object 数组; LinkedList 底层使用的是 双向链表 数据结构
  • 插入和删除是否受元素位置的影响:
    • ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行 add(E e) 方法的时候, ArrayList 会默认将指定的元素追加到末尾,这种情况时间复杂度就是 O(1)。但是如果要在指定位置 i插入和删除元素的话 add(int index, E element) ,时间复杂度就为O(n)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后移一位的操作。
    • LinkedList 采用链表存储,所以在头尾插入或者删除元素不受元素位置的影响( add(E e) 、 addFirst(E e) 、 addLast(E e) 、removeFirst() 、 removeLast() ),时间复杂度为 O(1),如果是要在指
      定位置 i 插入和删除元素的话( add(int index, E element) ,remove(Object o) , remove(int index) ), 时间复杂度为 O(n) ,因为需要先移动到指定位置再插入和删除。
  • 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而ArrayList (实现了 RandomAccess 接口) 支持。快速随机访问就是通过元素的下标快速获取元素对象(对应于 get(int index) 方法)。
  • 内存空间占用: ArrayList 的空间浪费主要体现在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。

另外,不要下意识地认为 LinkedList 作为链表就最适合元素增删的场景。我在上面也说了, LinkedList 仅仅在头尾插入或者删除元素的时候时间复杂度近似O(1),其他情况增删元素的平均时间复杂度都是 O(n) 。

4.1 关于ArrayList 的扩容机制

  • 以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为 10。
  • 以带参构造方法创建 ArrayList 时,初始容量是构造传入的参数值大小。
  • ArrayList 每次扩容之后容量都会变为原来的 1.5 倍左右
    • oldCapacity 为偶数就是 1.5 倍,否则是 1.5 倍左右
    • 扩容算法是 oldCapacity + (oldCapacity >> 1) (>>1 右移一位相当于除 2)
  • 关于ArrayList 的底层扩容源码:
private Object[] grow(int minCapacity) {
     int oldCapacity = elementData.length;
     if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
          int newCapacity = ArraysSupport.newLength(oldCapacity,
                  minCapacity - oldCapacity, /* minimum growth */
                  oldCapacity >> 1           /* preferred growth */);
          return elementData = Arrays.copyOf(elementData, newCapacity);
      } else {
          return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
      }
 }

5. Set接口

在这里插入图片描述

5.1 比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同

  1. HashSet 、 LinkedHashSet 和 TreeSet 都是 Set 接口的实现类,都能保证元素唯一,并且都不是线程安全的。
  2. HashSet 、 LinkedHashSet 和 TreeSet 的主要区别在于底层数据结构不同:
    • HashSet 的底层数据结构是哈希表(基于 HashMap 实现);
    • LinkedHashSet 的底层数据结构是链表和哈希表,元素的插入和取出顺序满足 FIFO。
    • TreeSet 底层数据结构是红黑树,元素是有序的,排序的方式有自然排序和定制排序。
  3. 底层数据结构不同又导致这三者的应用场景不同:
    • HashSet 用于不需要保证元素插入和取出顺序的场景
    • LinkedHashSet 用于保证元素的插入和取出顺序满足 FIFO 的场景
    • TreeSet 用于支持对元素自定义排序规则的场景

5.2 无序性和不可重复性的含义是什么

  • 无序性不等于随机性 ,无序性是指存储的数据在底层数组中并非按照数组索引的顺序添加 ,而是根据数据的哈希值决定的。
  • 不可重复性是指添加的元素按照 equals() 判断时 ,返回 false,需要同时重写equals() 方法和 hashCode() 方法。

6. HashSet 如何检查重复?

HashSet存储不重复的元素,那么向HashSet中添加元素时,是如何检查被添加的元素是否已经存在了呢?

当你把对象加入 HashSet 时, HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他加入的对象的hashcode 值作比较,如果没有相符的hashcode , HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode值的对象,这时会调用 equals() 方法来检查 hashcode 相等的对象是否真的相同。如果两者相同, HashSet 就不会让加入操作成功。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java集合大总结——Collection集合 的相关文章

  • 在 mvn 命令中指定 pom.xml 并混合其他项目的目标

    我有多个问题 我可以在 mvn 命令中指定 pom xml 吗 在当前项目上执行 mvn 命令时 我可以混合另一个项目的目标吗 例如 mvn clean otherproject comple otherproject install ot
  • 从 java sdk 向对等方发送提案时出现访问被拒绝错误

    我正在尝试使用以下代码查询区块链并收到访问被拒绝错误 我也遇到同样的错误sendTransactionProposal方法也是如此 UserContext adminUserContext RegisterEnrollUser regist
  • JPA 中的复合键

    我想创建一个具有自动生成的主键的实体 而且还有一个由其他两个字段组成的唯一复合键 我如何在 JPA 中执行此操作 我想这样做是因为主键应该用作另一个表中的外键 并且使其复合并不好 在下面的代码片段中 我需要命令和模型是唯一的 pk当然是主键
  • Spring Security 自定义过滤器

    我想自定义 Spring security 3 0 5 并将登录 URL 更改为 login 而不是 j spring security check 我需要做的是允许登录 目录并保护 admin report html 页面 首先 我使用教
  • 通过SOCKS代理连接Kafka

    我有一个在 AWS 上运行的 Kafka 集群 我想用标准连接到集群卡夫卡控制台消费者从我的应用程序服务器 应用程序服务器可以通过 SOCKS 代理访问互联网 无需身份验证 如何告诉 Kafka 客户端通过代理进行连接 我尝试了很多事情 包
  • GWT - 如何组织项目以拥有多个网页以及它们之间的导航

    我是 GET 的新手 顺便说一句 它给我留下了深刻的印象 并且发现它对于像我这样熟悉 C NET 桌面技术并愿意编写 Web 应用程序的人来说非常有吸引力 我根据 GWT Eclipse 向导生成的示例启动了自己的项目 该项目生成带有面板的
  • 通往楼梯顶部的可能路径

    这是一个非常经典的问题 我听说谷歌在他们的面试中使用过这个问题 问题 制定一个递归方法 打印从楼梯底部到楼梯顶部的所有可能的独特路径 有 n 个楼梯 您一次只能走 1 步或 2 步 示例输出 如果它是一个有 3 级楼梯的楼梯 1 1 1 2
  • 是否可以使用 Flying Saucer (XHTML-Renderer) 将 css 解析为类路径资源?

    我正在尝试将资源打包到 jar 中 但我无法让 Flying Saucer 在类路径上找到 css 我无法轻松构建 URL 来无缝解决此问题 https stackoverflow com questions 861500 url to l
  • Kotlin 未解决的参考:CLI 上 gradle 的 println

    放一个printlnkotlin 函数返回之前的语句会崩溃 堆栈跟踪 thufir dur NetBeansProjects kotlin thufir dur NetBeansProjects kotlin gradle clean bu
  • Spring Security SAML2 使用 G Suite 作为 Idp

    我正在尝试使用 Spring Security 5 3 3 RELEASE 来处理 Spring Boot 应用程序中的 SAML2 身份验证 Spring Boot 应用程序将成为 SP G Suite 将成为 IDP 在我的 Maven
  • 如何使用 Hibernate (EntityManager) 或 JPA 调用 Oracle 函数或过程

    我有一个返回 sys refcursor 的 Oracle 函数 当我使用 Hibernate 调用该函数时 出现以下异常 Hibernate call my function org hibernate exception Generic
  • 内部存储的安全性如何?

    我需要的 对于 Android 我需要永久保存数据 但也能够编辑 并且显然是读取 它 用户不应访问此数据 它可以包含诸如高分之类的内容 用户不得对其进行编辑 我的问题 我会 并且已经 使用过Internal Storage 但我不确定它实际
  • 读取电子邮件的文本文件转换为 Javamail MimeMessage

    我有一个电子邮件原始来源的文本文件 直接从 gmail 复制 如果您单击 查看原始文件 您就会看到它 我想读入该文件并将其转换为 MimeMessage 如果您好奇为什么 我设置了 JavaMaildir 并且需要用电子邮件填充它的收件箱以
  • HashMap 值需要不可变吗?

    我知道 HashMap 中的键需要是不可变的 或者至少确保它们的哈希码 hashCode 不会改变或与另一个具有不同状态的对象发生冲突 但是 HashMap中存储的值是否需要与上面相同 为什么或者为什么不 这个想法是能够改变值 例如在其上调
  • 如何在 Java 中创建接受多个值的单个注释

    我有一个名为 Retention RetentionPolicy SOURCE Target ElementType METHOD public interface JIRA The Key Bug number JIRA referenc
  • 是否可以使用 Java Guava 将函数应用于集合?

    我想使用 Guava 将函数应用于集合 地图等 基本上 我需要调整 a 的行和列的大小Table分别使所有行和列的大小相同 执行如下操作 Table
  • “无法实例化活动”错误

    我的一个 Android 应用程序拥有大约 100 000 个用户 每周大约 10 次 我会通过 Google 的市场工具向我报告以下异常情况 java lang RuntimeException Unable to instantiate
  • Java Swing:需要一个高质量的带有复选框的开发 JTree

    我一直在寻找一个 Tree 实现 其中包含复选框 其中 当您选择一个节点时 树中的所有后继节点都会被自动选择 当您取消选择一个节点时 树中其所有后继节点都会自动取消选择 当已经选择了父节点 并且从其后继之一中删除了选择时 节点颜色将发生变化
  • Hamcrest Matchers - 断言列表类型

    问题 我目前正在尝试使用 Hamcrest Matchers 来断言返回的列表类型是特定类型 例如 假设我的服务调用返回以下列表 List
  • 洪水填充优化:尝试使用队列

    我正在尝试创建一种填充方法 该方法采用用户指定的初始坐标 检查字符 然后根据需要更改它 这样做之后 它会检查相邻的方块并重复该过程 经过一番研究 我遇到了洪水填充算法并尝试了该算法 它可以工作 但无法满足我对 250 x 250 个字符的数

随机推荐

  • 高校软件工程期末复习——ICONIX

    ch01 软件工程危机 定义 软件在开发和维护过程中遇到的一系列严重的问题 含义 如何开发软件 如何维护数量不断膨胀的已有软件 原因 客户对软件需求的描述不精确 可能有遗漏 有二义性 有错误 在软件开发过程中 用户提出修改软件功能 界面 支
  • Cookie和Session是什么?它们的区别是什么?

    什么是Cookie Cookie实际上是一小段的文本信息 客户端请求服务器 如果服务器需要记录该用户状态 就使用response向客户端浏览器颁发一个Cookie 客户端会把Cookie保存起来 当浏览器再请求该网站时 浏览器把请求的网址连
  • 谷歌浏览器报错:NET::ERR_CERT_AUTHORITY_INVALID

    chrome net internals hsts
  • Vivado使用心得(六)Vivado ILA观察信号和调试过程

    先简单介绍一下ILA Integrated Logic Analyzer 生成方法 这里有两种办法完成Debug Core的配置和实现 方法一 mark debug综合选项 Set Up Debug设定ILA参数 1 在信号 reg或者wi
  • MV-YOLO翻译(2018年5月 CVPR论文)【原创】

    声明 作者翻译论文仅为学习 如有侵权请联系作者删除博文 谢谢 另 如有不当的地方 请各位大佬批评指正 谢谢 MV YOLO 通过语义目标检测实现运动矢量跟踪 原论文pdf下载地址 https arxiv org pdf 1805 00107
  • office2010 错误1706 解决办法

    office2010 错误1706 解决办法 问题描述 1 弹窗 无限弹窗 无限 困扰了我大概半年的问题 自从上次不小心删掉一些有关office2010的东西 导致网页中下载东西后总是弹窗 office2010 卸载出现 安装程序找不到Pr
  • 以太坊微支付通道原理与实现

    以太坊微支付通道原理与实现 线上直接转账需要一定的费用 如果存在大量小额交易的情况下 费用会变的难以承受 因而以太坊引入了微交易支付通道来解决这个问题 以太坊提供了一个票据支付方案 主要依赖于智能合约实现的一对多的账单系统 该账单系统大致上
  • 【超级无敌详细的韩顺平java笔记】从入门到精通---基本数据类型的转换

    1 自动类型转换 当Java程序在进行赋值或运算时 精度小的类型自动转换为精度大的数据类型 这个就是自动类型转换 数据类型按照精度 容量 大小排序为 注意和细节 1 有多种类型的数据混合运算时 系统首先自动将所有数据转换成容量最大的那种数据
  • kafka 配置部署

    本文以部署三台kafka broker 为例讲解 kafka版本为 kafka 2 9 2 0 8 1 1 运行环境为centos jdk版本为1 7以上 kafka依赖zookeeper 部署之前部署好zookeeper集群 1 获取ka
  • Linux中操作sqlite3、sqlite3数据c/c++接口编程与Windows和Linux中sqlite3库的制作(SQLite二)

    目录 一 linux操作sqlite3 1 可以像window下通过qtcreator编译 2 可以用gcc直接编译 1 要安装libreadline dev 2 在工程文件中添加 3 打开shell c 在最前面添加一行代码 3 直接用U
  • .net线程同步

    大家都晓得 NET中线程同步有以下几种方式 临界区 Critical Section 互斥量 Mutex 信号量 Semaphore 事件 Event 1 临界区 通过对多线程的串行化来访问公共资源或一段代码 速度快 适合控制数据访问 在任
  • element-ui的表单验证及自定义验证规则

    element ui是一个组件库 里面有很多项大家都会用到 其中的表单项验证时比较常用的 比如我们一个登录界面有以下的要求 手机号 必填 11位移动手机号 验证码 必填 6位数字 协议 必须勾选
  • 【NoteExpress】技巧与Error解决方案

    Error 插入文献出现 OLE error 800A01A8错 错误原因 未在源word wps文件插入文献时报错 解决方案 检查是否在源word wps文件中进行操作 点击 去除格式化 分别进行去除格式化 清除域代码操作 导入文献 出现
  • Java连接数据库(二):数据库连接池(druid)

    背景 每次使用SQL语句操作数据库的时候都需要创建一个与数据库的连接 使用完之后再把这个连接销毁掉 这种频繁创建与销毁比较耗费机器的性能跟资源 也没有太大意义 数据库连接可以解决该问题 备注 建立一个数据库连接是一件非常耗时 消耗时间 耗力
  • vue获取上传文件路径_VUE上传文件夹的三种解决方案

    1 背景 用户本地有一份txt或者csv文件 无论是从业务数据库导出 还是其他途径获取 当需要使用蚂蚁的大数据分析工具进行数据加工 挖掘和共创应用的时候 首先要将本地文件上传至ODPS 普通的小文件通过浏览器上传至服务器 做一层中转便可以实
  • 详解Arduino Uno开发板的引脚分配图及定义

    详解Arduino Uno开发板的引脚分配图及定义 在本篇文章中 我们将详细介绍Arduino开发板的硬件电路部分 具体来说 就是介绍Arduino Uno开发板的引脚分配图及定义 Arduino Uno微控制器采用的是Atmel的ATme
  • 【论文阅读】Learning Efficient Convolutional Networks through Network Slimming

    1 论文和代码 https arxiv org abs 1708 06519 https github com Eric mingjie network slimming 1 摘要 深度卷积神经网络 CNNs 在许多现实应用中的部署很大程度
  • 深入理解STL库

    关注本人公众号 获取更多学习资料 微信公众号搜索 阿Q正砖 上期说过C 这块面试问的东西也蛮多 简历上只要出现C 这几个字 那么STL库就是必问 总不能是面试官问你了解STL库吗 你尴尬的说这块不怎么熟悉 那这就 总的来说STL库这块也不是
  • Data modeling essentials

    数据库设计才是王道 1 Introduction 2 Normalization 3 ER图 4 Subtypes and Supertypes 5 Attributes and columns 6 Primary key 7 Extent
  • Java集合大总结——Collection集合

    Collection集合的整理 1 List Set Queue Map四者的区别 集合底层数据结构梳理 2 关于集合的的选用 2 1 为什么使用集合 3 List接口 3 1 ArrayList 和 Array 数组 的区别 3 1 Li