从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

  • JavaSenior

    • 反射

    • 注解

    • 集合类

      • 集合介绍
      • List
        • List 常用方法
        • of 方法
        • 遍历 List
        • List 和 Array 转换
        • equals 方法
        • 推荐阅读
      • Map
      • Set
      • Queue
      • Stack
      • Collections
    • 线程

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java
  • JavaSenior
  • 集合类
2022-12-31
目录

List

# List

在集合类中,List 是最基础的一种集合,可以理解为一种有序的线性表。

在数据结构里我们学过线性表,如果我们要往数组里添加或删除某个元素,需要挪动其他位置的元素;如果空间不够了,还要扩容。List 已经自动帮我们实现了这些,我们直接用就可以了,不用关心其内部怎么实现。

List 只是一个接口,常见的实现类有 ArrayList(用的最多,也推荐用)和 LinkedList,LinkedList 就相当于链表,两者的区别跟 数组和链表的区别一样。

List 接口允许我们添加重复的元素,还运行添加 null。

# List 常用方法

  • 在末尾添加一个元素:boolean add(E e)
  • 在指定索引添加一个元素:boolean add(int index, E e)
  • 删除指定索引的元素:E remove(int index)
  • 删除某个元素:boolean remove(Object e)
  • 获取指定索引的元素:E get(int index)
  • 获取链表大小(包含元素的个数):int size()
  • 是否含有某个元素:boolean contains(Object e)
  • 返回某个元素的索引:int indexOf(Object o)。如果元素不存在,就返回 -1。
List<String> myWaves = new ArrayList<>();
myWaves.add("爱莉希亚");
myWaves.add("布洛尼娅");
myWaves.add(0,"梅比乌斯");
String ss = myWaves.get(0);
System.out.println(ss);
System.out.println("myWaves.size(): " + myWaves.size());
1
2
3
4
5
6
7

运行结果:

梅比乌斯
myWaves.size(): 3
1
2

# of 方法

自 Java9 之后,可以通过 List 接口提供的 of() 方法,根据给定元素快速创建 List:

List<Integer> list = List.of(1, 2, 5);
1

该方法最多支持 10 个元素。注意事项:

  • 返回的只是一个只读 List,调用 add()、remove() 方法会抛出 UnsupportedOperationException。
  • List.of() 方法不接受 null 值,如果传入 null,会抛出 NullPointerException 异常。

如果使用 Java8,可以使用 Arrays.asList 方法来快速创建:

List<Integer> list = Arrays.asList(1, 2, 3);
1

Arrays.asList() 方法是 Arrays 的静态方法。这种方式构造的 List 是固定长度的,如果调用 add 方法增加新的元素时会报异常 java.lang.UnsupportedOperationException。这种方式仅适用于构造静态不变的 List。

# 遍历 List

遍历可以说是集合类最常用的方法了。我们可以用之前学过的遍历数组的方法来遍历:

for (int i = 0; i < myWaves.size(); i++) 
  System.out.println(myWaves.get(i));
1
2

但这种方式并不推荐,一是代码复杂,二是因为 get(int) 方法只有 ArrayList 的实现是高效的,换成 LinkedList 后,索引越大,访问速度越慢。

所以我们要始终坚持使用迭代器 Iterator 来访问 List。Iterator 本身也是一个对象,但它是由 List 的实例调用 iterator() 方法的时候创建的。Iterator 对象知道如何遍历一个 List,并且不同的 List 类型,返回的 Iterator 对象实现也是不同的,但总是具有最高的访问效率。

Iterator 对象有两个方法:boolean hasNext() 判断是否有下一个元素,E next() 返回下一个元素。因此,使用 Iterator 遍历 List 代码如下:

for(Iterator<String> it = myWaves.iterator(); it.hasNext(); ){
      System.out.println(it.next());
}
1
2
3

有童鞋可能觉得使用 Iterator 访问 List 的代码比使用索引更复杂。但是,要记住,通过 Iterator 遍历 List 永远是最高效的方式。并且,由于 Iterator 遍历是如此常用,所以,Java 的 for each 循环本身就可以帮我们使用 Iterator 遍历。把上面的代码再改写如下:

for (String s : myWaves) {
  System.out.println(s);
}
1
2
3

实际上,只要实现了 Iterable 接口的集合类都可以直接用 for each 循环来遍历,Java 编译器本身并不知道如何遍历集合对象,但它会自动把 for each 循环变成 Iterator 的调用,原因就在于 Iterable 接口定义了一个 Iterator<E> iterator() 方法,强迫集合类必须返回一个 Iterator 实例。

# List 和 Array 转换

把 List 变为 Array 有三种方法,

  • 调用 Object[] toArray() 方法直接返回一个数组:Object[] array = list.toArray(); 。但这样会丢失类型信息,较少用。
  • 给 toArray() 传入一个类型相同的 Array:Integer[] array = list.toArray(new Integer[3]);

如果我们传入的数组大小和 List 实际的元素个数不一致怎么办?根据 List 接口 (opens new window)的文档,我们可以知道:

如果传入的数组不够大,那么 List 内部会创建一个新的刚好够大的数组,填充后返回;如果传入的数组比 List 元素还要多,那么填充完元素后,剩下的数组元素一律填充 null。

实际上,最常用的是传入一个“恰好”大小的数组:

Integer[] array = list.toArray(new Integer[list.size()]);
1

把 Array 变为 List 就简单多了,通过 List.of(T...) 方法最简单:

Integer[] array = { 1, 2, 3 };
List<Integer> list = List.of(array);
1
2

对于 JDK 11 之前的版本,可以使用 Arrays.asList(T...) 方法把数组转换成 List。

# equals 方法

前面我们简单演示了下 contains() 方法,其内部是用 equals() 方法判断两个元素是否相等(indexOf() 也是用 equals() 来查找的)。如果我们存放的类型没有实现 equals() 方法,那么 contains() 方法是无效的,我们来演示下。

首先创建一个 Person 类,里面没有实现 equals 方法:

class Person {
  public String name;
  public int age;

  Person(String name, int age){
    this.name = name;
    this.age = age;
  }
}
1
2
3
4
5
6
7
8
9

然后测试 contains():

    List<Person> myWaves = new ArrayList<>();
    myWaves.add(new Person("雷姆", 18));
    myWaves.add(new Person("拉姆", 18));
    myWaves.add(new Person("艾米莉雅", 18));

    boolean b = myWaves.contains(new Person("雷姆", 18));
    System.out.println(b);  //false
1
2
3
4
5
6
7

可以看到,虽然我们创建了一样的 Person 类(name 和 age 相同),但是 contains() 返回的是 false

因此,要正确使用 List 的 contains()、indexOf() 这些方法,放入的实例必须正确覆写 equals() 方法,否则,放进去的实例,查找不到

至于实例是否 equals 是否相同,则是我们自己定义的逻辑。我们可以认为名字相同既是同一人,也可以认为名字和年龄都一样才是同一人。我们完善 Person 类如下:

class Person {
  public String name;
  public int age;

  Person(String name, int age){
    this.name = name;
    this.age = age;
  }

  public boolean equals(Object o){
    if(o instanceof Person){
      Person p = (Person) o;
      return this.name.equals(p.name) && this.age == p.age;
    }
    return false;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

此时我们再使用 contains() 方法,就可以判断是否存在某个实例了。

不过,此时的方法还不完善:

  1. 如果 this.name 为 null,会报错空指针异常
  2. 如果有多个引用类型,那么判空的代码就更多了,可以使用 Objects.equals() 静态方法。

# 推荐阅读

LinkedList 的作者说他自己都不用 LinkedList? (opens new window)

上次更新: 2024/10/1 18:45:09
集合介绍
Map

← 集合介绍 Map→

最近更新
01
学点统计学:轻松识破一本正经的胡说八道
06-05
02
2025 年 5 月记
05-31
03
《贫穷的本质》很棒,但可能不适合你
05-27
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式