news 2026/2/7 8:50:23

java学习日志--集合(Collection篇)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
java学习日志--集合(Collection篇)

一、集合框架

1.1 集合概述

集合:广义上的集合简单理解就是容器。需要注意的是,集合只能存放对象类型的数据。

所以如果你要存放基本数据类型的数据是不能直接存储的,需要转化成包装类,包装类详见常见类库(下)。

1.2 集合框架

集合框架是Java中非常重要的技术体系,在日常开发中无处不在。

集合框架指的是java.util包中定义的各种容器类、相关的工具类、接口的统称。不同的容器存储不同结构的数据。使用时要进行导包操作。

具体集合的框架的体系图如下:

其中,Iterator是根部的父接口,总结来说,接口一共分为两大类(三小类),分别是Collection和Map(List,Set和Map)。

具体特性如上图所示(以下无序是指在逻辑上的有无序),

List是有序可重复的集合,实现类有ArrayList,LinkedList;

Set是无序不可重复的集合,实现类有HashSet,TreeSet,LinkedHashSet;

Map里面存放的是无序的具有映射关系的键值对,实现类有HashMap,LinkedHashMap,TreeMap。

二、Collection接口

2.1 Collection接口概述

具体Collection接口的类结构见1.2中的图所示,实际上,其中TreeSet上面是有一个父类SortedSet的,后面的某一个点会有要提到的地方。

在常见类库(上)中我们我们有提到,了解一个类可以从它的定位,也就是作用,和它的构造器,以及它的成员来学习,同样,接触到了一个新的接口,我们先看一下它的结构。

Collection接口继承了Iterator,在Iterator接口中,规定了实现类必须要提供迭代器对象,在Java中使用迭代器去遍历集合中的元素,这是一种新的遍历方法,在学习此之前都是循环遍历。

Collection作为Iterable接口的子接口,意味着Collection接口的实现类一定会实现Iterable接口中规定的方法;List、Set接口的实现类也一定会实现Iterable接口中规定的方法。

2.2 Collection接口的方法

因为它是一个接口,所以其中定义的大多都是抽象方法,是没有方法体的。

详细的方法如下:

//获取集合中元素的个数。 int size() //向集合中添加元素,添加后如果容器内容发生了变化,返回true,否则返回false。 //有些容器不允许重复元素。 boolean add(E e) //将指定集合中的元素添加到当前集合中,添加后如果容器内容发生了变化,返回true,否则返回false。 booleanaddAll(Collection <? extends E > c) //从集合中删除指定的元素,删除后如果容器内容发生了变化,返回true,否则返回false。 boolean remove(Obiect 0) //删除指定集合中包含的全部元素,删除后如果容器内容发生了变化,返回true,否则返回false。 boolean removeAl(Collection<?>c) //删除集合中全部元素。 void clear() //判断集合中是否包含指定的元素。 boolean contains(Object0) //判断集合中是否包含指定集合中全部元素。 boolean containsAll(Collection<?> c) //获取集合对应的迭代器。(迭代器可以遍历集合) Iterator<E>iterator() //判断是不是空集合 boolean isEmpty() //将集合转换成对象数组。 Object[] toArray()

因为List接口和Set接口继承了该接口,所以这些方法在这些接口及其实现类中也是可以调用的,如果没有涉及到改动,在下面的讲述中就只总结新遇到的方法。

三、List接口

3.1 List接口概述

List 是一个“有顺序、可重复”的集合,像排队一样,每个元素都有固定位置(索引),所以这个有序指的是逻辑是否有序。

因为存在下标,所以List可以利用下表去做一些不同的事,也就是它定义了自己的一些关于下标的方法。

3.2 List接口的方法

//在集合指定的位置添加元素。 void add(int index,E e) //在集合中指定的位置添加一组元素 void addAll(int index, Collection<?extends E> c) //获取集合中指定位置的元素。 E get(int index) //获取对象第一次出现在集合中的下标。如果没有这个对象返回-1。 int indexOf(Object o) //获取对象最后一次出现在集合中的下标。如果没有返回-1。 int lastindexOf(Object o) //删除指定下标的元素,返回值是被删除的元素。 E remove(int index) //将指定位置的元素修改成e,返回值是此位置原来的元素。 E set(int index, E e) //获取子列表。不含toIndex对应的元素 List< E> subList(int fromIndex, int tolndex)

3.3 List接口的实现类

因为讲的是集合,集合是要存放数据的,关于数据就要涉及到增删改查,这方面是重点,所以下面我们重点介绍一下相关的增删改查的一些方法。

3.3.1 ArraysList实现类

ArraysList实现类的底层逻辑是数组,有关数组的逻辑在这里就不再多讲了吧,如果对数组的内存有疑问也可以去查看我之前的文章。

同时,这个数组存放又和我们之前的数组有些不同,ArrayList是长度可变的数组,长度不足时会自动扩充容量。

由于底层是靠数组完成的数据存取,所以查询效率高(根据index查询),增删效率低。

具体逻辑:因为数组有下标,根据索引可以很快地找到对应的数据,但是又因为数组结构在存放上是物理有序的,所以当我们需要增删时,我们需要随之对后续的数据都要进行前移或后挪,所以查询效率高(根据index查询),增删效率低。

3.3.1.1 构造器
//创建一个初始容量为10的空列表。 ArrayList() //创建一个列表,包含参数中全部的元素,顺序与参数中元素的顺序一致。 ArrayList(Collection<? extends E> c) //创建一个指定容量的空列表。 ArrayList(int capacity)
3.3.1.2 增删改查

1)增

//向ArrayList中添加一个元素,元素会添加到ArrayList的末尾。如果添加成功,返回true boolean add(E e) //在指定位置插入元素。 void add(int index, E e) //将指定集合中的数据按顺序添加到ArrayList的末尾。 boolean addAll(Collection<? extends E> c) //将指定集合中的数据插入到ArrayList的指定的位置。 boolean addAll(int index, Collection<? extends E> c)

2)删

//从列表中删除指定的元素,如果有多个,只会删除第一个。如果成功删除返回true,如果没有删除返回false。 boolean remove(Object o) //删除指定位置的元素。返回值是被删除的元素。 E remove(int index) //从列表中删除指定集合中包含的元素。如果列表删除了数据返回true,否则返回false。 boolean removeAll(Collection<? extends E> c) //清空列表中的元素 void clear()

3)改

E set(int index, E e) //将指定下标的元素修改为e

4)查

  • 是否包含此元素
//判断列表中是否包含指定的元素,如果包含返回true,否则返回false。 boolean contains(Object o)
  • 获取指定下标的元素
E get(int index) //获取指定下标处的元素。
  • 根据元素获取下表
//返回列表中指定元素第一次出现的下标。如果没有指定元素返回-1 int indexOf(Object o) //返回列表中指定元素最后一次出现的下标。如果没有指定元素返回-1 int lastIndexOf(Object o)
  • 获取列表中元素的个数
int size() //获取列表中元素的个数
3.3.1.3 ArraysList的遍历

作为数组的存储方式,ArraysListu也可以使用普通for循环进行遍历。

  • 通过普通for循环遍历
for(int i = 0; i < arrayList.size(); i++){ arrayList.get(i); }
  • 加强for循环
for(数据类型 对象 : arrayList){ 对象;//对象就是遍历出来的数据 }
  • 迭代器循环
//调用iterator方法返回的值赋给新建的Iterator对象,使用该对象调用对应的方法进行迭代器循环 Iterator<数据类型> it = arrayList.iterator(); while(it.hasNext()){ 数据类型 对象 = it.next(); }

3.3.2 LinkedList实现类

LinkedList底层是靠双向链表来存放元素的。链表中的元素在逻辑上连续,但物理上不连续。因此,LinkedList增、删效率高,增删元素无需做任何移动,直接改变链表的指向即可。但根据下标查找元素效率低。

3.3.2.1 构造器
//创建一个空列表。 LinkedList() //创建一个列表,包含参数中全部的元素,顺序与参数中元素的顺序一致。 LinkedList(Collection<? extends E> c)
3.3.2.2 增删改查

因为都是有下标的集合,所以在增删改查方面和ArraysList基本相同,由于内容较多,在此就不再多赘述,详细查看3.3.1.2 。

3.3.2.3 LinkedList的遍历

  • 通过普通for循环遍历
for(int i = 0; i < LinkedList.size(); i++){ LinkedList.get(i); }
  • 加强for循环
for(数据类型 对象 : LinkedList){ 对象;//对象就是遍历出来的数据 }
  • 迭代器循环
//调用iterator方法返回的值赋给新建的Iterator对象,使用该对象调用对应的方法进行迭代器循环 Iterator<数据类型> it = LinkedList.iterator(); while(it.hasNext()){ 数据类型 对象 = it.next(); }

四、Set接口

4.1 Set接口概述

Set接口规定了无序(无下标),元素不可重复的容器应该具有什么功能。既然是不含重复元素的集合,那它就具有排除重复元素的能力。

所以我们在进行Set接口的总结时也要加上它相关的去重原理。

4.2 Set接口的方法

Set接口中并没有声明多少独特的方法,而是声明了和父接口相同的方法。

所以具体的方法和Collection接口,也就是父接口中的相同,再次也不过多赘述,详情请见2.2内容

4.3 Set接口的实现类

4.3.1 HashSet实现类

HashSet实现类中存储的数据是不重复的,元素的顺序也是无序的。底层数据结构是哈希表。

在学习这一块时我问过AI,它给了我一个比较形象的例子,说它就像是你要往一面墙上贴照片,墙上的每个位置都有一个自己的编码(哈希码),当来了一个照片(数据),就会根据它的内容找到(生成)一个位置(哈希码),然后贴上去。如果墙上的那个位置已经存在照片,就说明已经贴过了,这就是一种查重。

4.3.1.1 HashSet的构造器
//创建一个空集合,集合的初始容量是16,加载因子是0.75 HashSet() //创建一个包含指定元素的集合,会去除重。加载因子是0.75 HashSet(Collection<? extends E> c) //创建一个指定初始容量的空集合。加载因子是0.75 HashSet(int capacity) //创建一个空集合,指定初始容量和加载因子。 HashSet(int capacity, float loadFactor)
4.3.1.2 HashSet的方法

1)增

//向集合中添加一个元素,如果添加成功,返回true boolean add(E e) //将指定集合中的数据添加到HashSet中,会去重。 boolean addAll(Collection<? extends E> c)

2)删

//从集合中删除指定的元素,如果成功删除返回true,如果没有删除返回false(例如:没有指定的元素)。 boolean remove(Object o) //从HashSet中删除指定集合中包含的元素。如果删除了数据返回true,否则返回false。 boolean removeAll(Collection<? extends E> c) //清空集合中的元素 void clear()

3)改

因为HashSet没有下标,且是无序的,所以无法进行修改数据,所谓的修改,是通过for循环或者迭代器进行的一种删除数据再添加的操作。

4)查

//判断集合中是否包含某元素 boolean contains(Object o) //获取集合中元素的个数。 int size()
4.3.1.3 HashSet的去重机制

我们可以先将List集合转化成Set集合,再转换回来,就可以达到去重的目的。

1)先判断对象的hashCode是否一样,如果hashCode不同,认为是不同的元素。如果hashCode相同,进入下面的判断。

2.)判断equals方法返回值是true还是false,如果是false认为是不同的元素,如果是true认为是元素重复。不再添加进集合。

3)hashCode可以通过重写根类Object的hashCode()方法来返回一个hashCode值。

但是当我们new两个对象,但是他们的内容完全相同,对于代码而言,他们就是不同的,因为内存地址不同,但是从逻辑上来看,他们就是完全重复的内容。这时候,我们可以通过重写对应类里的hashCode和equals方法,来达到根据我们的条件去重的目的。

4.3.1.4 HashSet的遍历

因为没有下表,所以无法使用普通for循环来进行遍历

  • 加强for循环
for(数据类型 对象 : HashSet){ 对象;//对象就是遍历出来的数据 }
  • 迭代器循环
//调用iterator方法返回的值赋给新建的Iterator对象,使用该对象调用对应的方法进行迭代器循环 Iterator<数据类型> it = HashSet.iterator(); while(it.hasNext()){ 数据类型 对象 = it.next(); }

4.3.2 LinkedHashSet实现类

LinkedHashSet是HashSet的子类,它具有和HashSet同样的功能,元素也是不能重复,唯一不同的是,LinkedHashSet会维持元素加入的顺序。LinkedHashSet和LinkedList一样,底层数据结构是双向链表+哈希表。

4.3.2.1 LinkedHashSet的构造器
//创建一个空集合,集合的初始容量是16,加载因子是0.75 LinkedHashSet() //创建一个包含指定元素的集合,会去除重。加载因子是0.75 LinkedHashSet(Collection<? extends E> c) //创建一个指定初始容量的空集合。加载因子是0.75 LinkedHashSet(int capacity) //创建一个空集合,指定初始容量和加载因子。 LinkedHashSet(int capacity, int loadFactor)
4.3.2.2 LinkedHashSet的方法

因为LinkedHashSet是HashSet的子类,所以详情见4.3.1.2,

4.3.2.3 LinkedHashSet的遍历

见HashSet的遍历4.3.1.4

4.3.3 TreeSet实现类

TreeSet使用的是二叉树存储元素, 通过中序遍历的方式来遍历(检索)元素

二叉树的遍历有3种方式,先序遍历,中序遍历和后序遍历。无论是否哪种遍历方式.都是从树根开始查看的 。

先序:先父节点,再左,最后右ABDECFG

中序:先左,再父,最后右DBEAFCG

后序:先左,再右,最后父DEBFGCA

TreeSet实现类会有一个默认的排序,第一个进入的值在根位置,之后进来的元素都会和第一个元素进行比较,比根小就在左边,比根大就在右边。

4.3.3.1 TreeSet的构造器
//创建一个空集合,根据内部元素的自然顺序排序。 TreeSet() //创建一个包含指定元素的集合,根据内部元素的自然顺序排序。 TreeSet(Collection<? extends E> c) //创建一个空集合。根据指定的比较器进行排序。 TreeSet(Comparator<? super E> comparator) //创建一个与参数一样的集合,按参数的顺序组织元素顺序。 TreeSet(SortedSet<E> s)
4.3.3.2 TreeSet的方法

基本和HashSet的方法相同,在这里我举几个独有的方法吧

//获取集合倒序的迭代器对象 Iterator< E > descendingIterator() //获取集合第一个元素 E first() //获取结合最后一个元素 E last() //获取从from到to的元素。 SortedSet< E > subSet(E from, E to)
4.3.3.3 TreeSet的去重方法

去重和内容有序的原理: 第一个加入set的元素, 会成为树的根, 从第二个元素开始, 要和set中已有的元素比较大小, 如果要添加的元素 大于了已有元素,放在元素右侧, 如果小于了已有元素, 放左侧, 如果要添加的元素和已有元素相等, 会认为重复, 不进行添加 。

4.3.3.4 TreeSet的遍历

因为也是没有下标,所以在遍历方面也基本和HashSet相同,唯独多了一个倒序迭代器,如下。

Iterator<String> it = set.descendingIterator(); while(it.hasNext()) { String str = it.next(); System.out.println(str); }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/6 17:53:00

DOOM-3-BFG内存安全防护完整教程:从危险函数到安全编码实践

DOOM-3-BFG内存安全防护完整教程&#xff1a;从危险函数到安全编码实践 【免费下载链接】DOOM-3-BFG Doom 3 BFG Edition 项目地址: https://gitcode.com/gh_mirrors/do/DOOM-3-BFG 在游戏开发领域&#xff0c;内存安全是确保软件稳定性和安全性的基石。作为经典射击游戏…

作者头像 李华
网站建设 2026/2/6 19:11:46

【第十一天】11c#今日小结

1.冒泡排序 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace _03冒泡和选择 {internal class Program{static void Main(string[] args){//冒泡排序:俩两相比&#xff0c;如果前面大于后面的…

作者头像 李华
网站建设 2026/2/3 16:43:34

从Git下载到本地运行:FLUX.1-dev大模型部署全步骤详解

从Git下载到本地运行&#xff1a;FLUX.1-dev大模型部署全步骤详解 在生成式AI的浪潮中&#xff0c;越来越多开发者不再满足于调用云端API——他们想要更安全、可控且可定制的图像生成能力。尤其是在处理敏感内容或进行高频实验时&#xff0c;依赖外部服务不仅成本高昂&#xff…

作者头像 李华
网站建设 2026/2/5 17:51:26

DeepSeek-AI突破:OCR模型文本压缩效率提升20倍

当我们谈论人工智能的发展时&#xff0c;有一个有趣的现象值得关注&#xff1a;人类能够一眼看到一张包含大量文字的图片&#xff0c;就立刻理解其中的内容&#xff0c;但让计算机做同样的事情却异常困难。更有意思的是&#xff0c;如果我们能让计算机像人类一样"看图读字…

作者头像 李华
网站建设 2026/2/5 22:59:04

百度网盘智能提取码神器:告别繁琐搜索的效率革命

还在为百度网盘提取码四处翻找而头疼吗&#xff1f;每次看到心仪的资源&#xff0c;却因为找不到提取码而望洋兴叹&#xff1f;BaiduPanKey正是为你量身打造的智能解决方案&#xff0c;让提取码获取变得像复制粘贴一样简单&#xff01;&#x1f680; 【免费下载链接】baidupank…

作者头像 李华
网站建设 2026/2/3 16:05:28

Vue3后台管理系统终极指南:开箱即用的Element Plus管理模板

Vue3后台管理系统终极指南&#xff1a;开箱即用的Element Plus管理模板 【免费下载链接】vue-next-admin &#x1f389;&#x1f389;&#x1f525;基于vue3.x 、Typescript、vite、Element plus等&#xff0c;适配手机、平板、pc 的后台开源免费模板库&#xff08;vue2.x请切换…

作者头像 李华