Java集合
创始人
2024-04-06 18:27:01
0

一、集合概述


1、数组的特点

  • 数组的大小是固定的,一旦创建后,数组的大小是无法改变的。
  • 数组只能存储相同类型的数据。
  • 数组查询效率高(有索引,元素内存连续分配),增删效率低(不断的扩容)。

2、数组和集合的区别

相同点:

  • 都是容器,都可以存储多个数据。
  • 都可以存储引用类型的数据。

区别:

  • 数组长度不可变。
  • 集合长度可变。
  • 数组既可以存储基本类型数据,也可以存储引用类型数据。
  • 集合只能存储引用类型数据,如果要存储基本类型,需要存储对应的包装类。

3、为什么要用集合?

数组的缺点: 不灵活,容量需要事先定义好,不能随着需求的变化而扩容。

但是我们的开发又不可能离开数组,所以最初就只能依靠一些数据结构来实现动态的数组处理,其中最为重要的两个数据结构:链表、数组,但是面对这些数据结构的实现又不得不面对如下的问题?

  • 数据结构的代码实现困难,对于一般的开发者是无 法进行使用的。

  • 对于链表或二叉树当进行更新处理的时候维护是非常麻烦的。

  • 对于链表或二叉树还需要尽可能保证其操作的性能。


正是因为这样的原因,所以从JDK1.2开始Java引入了集合的概念,主要就是对常见的数据结构进行完整的实现包装,并且提供了一些列接口和实现类来帮助用户减少数据结构所带来的开发困难。

最初的集合实现由于Java本身的技术所限,所以对数据的控制并不严格,全部采用了Object类型进行数据的接收;在JDK1.5之后由于泛型技术的推广,集合框架也得到了良好的改进,可以直接利用泛型来保存相同类型的数据;随着数据量的不断增加,从JDK1.8开始集合框架中的实现算法也得到了良好的性能提升。

image-20221109173759470

二、Collection集合


java.util.Collection 是单列集合操作的最大的父接口,在该接口中定义了单列集合的所有操作。

在这里插入图片描述

Collection接口实现类的特点:

  • 有些Collection的子接口/实现类,可以存放重复的元素,有些不可以。
  • 有些Collection的子接口/实现类,有些是有序的(如 List),有些不是有序的(如 Set)。
  • Collection接口没有直接的实现子类,是用过它的子接口Set和List来实现的。

1、Collection集合常用方法

方法名称功能
boolean add(E e)添加单个元素
boolean addAll(Collection coll)把coll集合中的所有元素复制一份,并添加到当前集合中
void clear()清空集合中的所有元素
boolean contains(Object o)判断当前集合中是否包含指定的数据 (需要equals方法支持)
boolean isEmpty()判断当前合是否为空
boolean remove(Object o)删除(有相同元素,只能删除一个)(需要equals方法支持)
int size()获取集合中元素的个数
Object[] toArray()将集合变成Object数组返回
Iterator iterator()返回此集合中元素的迭代器

在进行集合操作的时候有两个方法最为常用:【添加数据】add()、【输出数据】iterator(),在JDK1.5版本之前Collection只是一个独立的接口,但是从JDK1.5之后提供了Iterable父接口,并且在JDK1.8之后 Iterable 接口也得到一些扩充。

但是往往我们玩的都是Collection的两个子接口: List(有序有索引可重复)、Set(无序不可以重复)接口。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-adjokWQR-1668175055586)(Java%E9%9B%86%E5%90%88.assets/image-20221109175927326.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CKI9L0Tm-1668175055586)(Java%E9%9B%86%E5%90%88.assets/image-20221109180206700.png)]


使用场景的总结:

1、如果希望元素可以重复,又有索引,索引查询要快?

  • 用 ArrayList集合,基于数组的。(用的最多,例如获取用户数据等等)

2、如果希望元素可以重复,又有索引,增删首尾操作快?

  • 用 LinkedList集合,基于链表的。(栈、队列、排队系统)

3、如果希望增删改查都快,但是元素不重复、无序、无索引。

  • 用 HashSet集合,基于哈希表的。

4、如果希望增删改查都快,但是元素不重复、有序、无索引。

  • 用 LinkedHashSet集合,基于哈希表和双链表。

5、如果要对对象进行排序。

  • 用 TreeSet集合,基于红黑树。后续也可以用List集合实现排序(sort方法)。

2、Collection集合的遍历元素

(1)使用Iterator(迭代器)遍历

我们知道Collection继承了Iterable接口,而在Iterable接口中定义了一个iterator()抽象方法,用于返回一个Iterator对象即迭代器对象,来遍历集合中所有元素。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cdHvnqm8-1668175624271)(Java%E9%9B%86%E5%90%88.assets/image-20221109205507959.png)]

而在Collection接口中重写了Iterable接口的iterator()方法,所以Collection的 子接口/实现类 都会有这个iterator()方法。

在这里插入图片描述
在这里插入图片描述

  • Iterator对象称为迭代器,主要用于遍历 Collection 集合中的元素。(因为它不能使用for+get(索引)方式取元素)
  • 所有实现了Collection接口的集合类都有一个iterator()方法,用于返回一个Iterator接口的实现类对象,即迭代器对象。
  • Iterator仅用于遍历集合,Iterator本身并不存放对象。


Iterator接口中的方法:

方法功能
boolean hasNext()如果仍有元素可以迭代,则返回 true
E next()返回迭代的下一个元素。
default void remove()使用迭代器删除集合中的元素,它会自动更新迭代器,并且更新集合。

迭代器的执行原理:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2sUCo2Cp-1668176087761)(Java%E9%9B%86%E5%90%88.assets/image-20221109222556515.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8V2Pz6SF-1668176087762)(Java%E9%9B%86%E5%90%88.assets/image-20221109222446475.png)]

迭代器源代码分析:

在这里插入图片描述

注意:

  • 在调用next()方法之前必须先调用hasNext()方法来检测下一个元素是否存在。若不调用且下一条记录无效时(也就是已经遍历完所有元素),再调用next()会抛出NoSuchElementException异常。

  • 当while循环结束后,iterator迭代器会指向最后一个元素,如果希望再次遍历集合,需要重新获取新的迭代器对象。

  • 如果在迭代器中添加删除指定元素,则会报ConcurrentModificationException并发修改异常。

    • 参考:https://blog.csdn.net/yztfst/article/details/97834440
  • 如果要在迭代器中删除指定元素,需要调用iterator的remove()方法,他会自动更新迭代器,并且更新集合。


(2)使用增强for循环遍历

增强for循环,JDK1.5新特性

增强for循环可以代替iterator迭代器,它只能用于遍历数组或集合。

语法格式:

for(元素类型 变量名 :集合或数组名){sout(变量名)
}

如果遍历数组:foreach底层源码是普通for循环。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pHPiOcge-1668180400683)(Java%E9%9B%86%E5%90%88.assets/image-20221109230502773.png)]


如果遍历集合:foreach底层源码是iterator迭代器(简化版的迭代器),只能对集合进行遍历操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXXgjYUU-1668180400683)(Java%E9%9B%86%E5%90%88.assets/image-20221109230702124.png)]

扩展:使用指定编码编译 javac -encoding utf-8 xx.java


三、常见的数据结构

数据接口有:数组、队列、栈、链表、树、散列、堆、图。

1、栈

特点:先进后出、后进先出、入栈(压栈)、出栈(弹栈)。


2、队列

特点: 先进先出、后进后出(例如排队做核酸)

在这里插入图片描述


3、数组

特点:查询快(有索引、元素内存连续分配)、增删慢(不断扩容)。

在这里插入图片描述


4、链表

特点:查询慢(需要遍历),增删快(不需要创建新的链表,只需修改链表中节点保存的地址)。

单项链表:
在这里插入图片描述


双向链表:
在这里插入图片描述

链表查询慢的原因:

  • 它需要遍历链表中的节点,然后使用算法判断是从前向后查,还是从后向前查。
  • 从前向后查:要查询节点的编号<节点数/2 。
  • 从后向前查:要查询节点的编号>=节点数/2。

5、树

在这里插入图片描述

  • 结点:树中的数据元素都称为结点。例如 A、B、C、D、E等等
  • 根:最上面的结点称之为根,一颗树只有一个根且由根发展而来,从另外一个角度来说,每个结点都可以认为是其子树的根。
  • 父亲:结点的上层结点,如图中,结点K的父亲是E、结点L的父亲是G。
  • 结点的度:结点所拥有的子树的个数称之为结点的度,如结点B的度为3
  • 树叶:度为0的结点,也叫作终端结点,图中D、K、F、L、H、I、J都是树叶。
  • 分支结点:度不为0的结点,也叫作非终端结点或内部结点,图中根、A、B、C、E、G都是分支结点
  • 结点的层次:从根节点到树中某结点所经路径上的分支树称为该结点的层次,根节点的层次规定为1,其余结点的层次等于其父亲结点的层次+1。

二叉树

二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。(左边小、右边大)

在这里插入图片描述


查找二叉树

二叉树的一个重要应用是在它们查找中的使用,假设树中的每个结点存储一项数据,使得二叉树成为二叉查找树的性质是:对于树中的每个结点X,它的左子树中所有项的值小于X,而它的右子树中所有项的值大于X,这意味着该树所有的元素可以用某种一致的方式排序。

在这里插入图片描述


平衡二叉树

在生成二叉树/二叉查找树的时候是非常容易失衡的,造成的最坏的情况就是一边倒(只有左子树/右子树),这样将会导致树的检索效率大大降低,所以为了维持二叉树的平衡,大牛们提出了各种实现的算法,比如:AVL树–每个结点的左子树和右子树深度最多差1。

在这里插入图片描述


红黑树

红黑树顾名思义就是结点是红色或者黑色的平衡二叉树,它通过颜色的约束来维持着二叉树的平衡。

对于一颗有效的红黑树而言我们必须增加如下规则:

  • 每个结点都只能是红色或者黑色;
  • 根节点是黑色;
  • 每片叶子都是黑色的;
  • 如果一个结点是红色的,则它的两个子节点都是黑色的,也就是说在一条路径上不能出现相邻的两个红色结点;
  • 从任意一个结点到其每个叶子的所有路径都包含着相同数目的黑色结点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BMJz2C51-1668183144235)(4_红黑树.png)]

这些约束强制了红黑树的关键性质:从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果就是这棵树大致上是平衡的,因为插入、删除和查找某个值得最坏情况时间都要求与树的高度成比例,这个高度理论上限允许红黑树只在最坏情况下都是高效的。


四、泛型


1、泛型概述

集合它可以存放任意对象,当把对象存储到集合后,他们都会被提升成Object类型。然后我们再取出每一个对象并且进行相应操作时,必须采用强制类型转换。

public class Demo01Generic {public static void main(String[] args) {// 创建一个ArrayList集合对象,指定存储数据的类型为StringArrayList list = new ArrayList<>();list.add("aa");list.add("bbb");list.add("cccc");// 将运行时异常,提前到了编译时期,降低了程序员的工作量//list.add(1000); //只能存String类型数据// 使用增强for进行遍历for (String str : list) {System.out.println(str + "的长度: " + str.length());}System.out.println("===================");// 创建集合,不指定存储数据的类型// 默认按照Object类型处理ArrayList list2 = new ArrayList();list2.add("aa");list2.add("bbb");list2.add("cccc");// 可以存// 但是取出来进行强制类型转换,报出类型转换异常list2.add(2022);// 使用增强for进行遍历for (Object obj : list2) {// 因为创建ArrayList集合对象时,并没有指定存储数据的类型(泛型),// 所以内部存储的所有内容均被当做Object类型处理// 必须做强制类型转换(向下转型),存在安全隐患:类型转换异常 ClassCastExceptionString str = (String) obj;System.out.println(obj + "的长度: " + str.length());}}
}

在这里插入图片描述
为什么会报错ClassCastException?因为上述的ArrayList集合只能存储同一类型对象(例如list2存储的都是字符串对象),当取出String类型数据时需要强转,即Object强转成String,又因为元素2022它强转后是Integer而不是String类型,所以把Integer类型的数据赋值给String类型后就会报ClassCastException类型转换异常。

如何解决:使用泛型来约束集合存储指定类型数据。(泛型,可以在类或方法中预支地使用未知的类型。)

(1)那使用泛型有哪些好处?

  • 可以避免强制类型转换的麻烦;
  • 将运行时异常,提前到了编译时期,降低了程序员的工作量;
  • 一旦指定泛型,数据类型将被统一;
  • 实现代码的模板化,把数据类型当做参数传递。

使用泛型的好处

定义和使用

泛型通配符


五、List集合


ArrayList

LinkedList


六、Set集合


HashSet

LinkedHashSet

TreepSet


七、Map集合


HashMap

LinkedHashMap

TreeMap

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
AWSECS:哪种网络模式具有... 使用AWS ECS中的awsvpc网络模式来获得最佳性能。awsvpc网络模式允许ECS任务直接在V...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...