张小飞的Java之路——第三十一章——List
bigegpt 2024-10-12 06:08 7 浏览
写在前面:
视频是什么东西,有看文档精彩吗?
视频是什么东西,有看文档速度快吗?
视频是什么东西,有看文档效率高吗?
1. 介绍
张小飞:我看 List 也是一个接口
诸小亮:是的,它是 Collection 下最常用的子接口之一,有自己独有的特点
- List:列表容器
- 存储的元素是有序的(存储的顺序和取出的顺序一致)
- 每个元素都有对应的下标,类似数组,所以可以通过下标获取元素
- 允许存储重复元素
张小飞:原来如此,那么它都有哪些实现类呢?
诸小亮:按照数据结构(存储数据的方式)划分,它的实现类有3个:
- ArrayList:最经常用的子类,底层使用可变数组存储数据
- LinkedList:底层使用链表存储数据
- Vector:底层也是可变数组,但不常使用,因为效率比 ArrayList 低
2. List的特有方法
张小飞:我们刚才用的就是 ArrayList
诸小亮:是的,不过,在讲解它的实现类之前,我们先看一下 List 接口的特有方法
1. add(int index, E e)
add(int index, E e):往指定位置插入元素,比如:
public static void main(String[] args) throws Exception {
List list = new ArrayList();
list.add("王昭君");
list.add("甄姬");
list.add(0,"嫦娥");//往指定位置添加元素,0表示第一个位置
System.out.println(list);
}
结果:
张小飞:这个参数 E 是什么意思?
诸小亮:这时泛型的意思,我们之后会详细解释的
2. remove(int index)
remove(int index):删除指定位置的元素,并返回这个元素
结果:
3. get(int index)
get(int index):获取指定位置的元素,经常使用
结果:
张小飞:如果指定的 index 不存在呢?
诸小亮:跟数组一样,会报异常,比如:
结果:
4. set(int index, E e)
set(int index, E e):修改指定位置的元素
结果:
5. for循环
诸小亮:List 类型的集合,可以使用 for 循环遍历,比如:
public static void main(String[] args) throws Exception {
ArrayList list = new ArrayList();
list.add("王昭君");
list.add("甄姬");
list.add(0,"嫦娥");
for(int i =0;i<list.size();i++){// 经常使用
System.out.println(list.get(i));
}
}
张小飞:原来还可以这样,我正想说用那个 Iterator 很不方便呢
诸小亮:确实,所以工作用我们一般都用 for 循环
6. ListIterator
诸小亮:ListIterator 是 List 集合的特有迭代器
张小飞:不是已经有 Iterator 了吗,怎么又来一个?
诸小亮:这式因为,在使用迭代器遍历 List 的时候,不能添加或删除元素,比如:
结果:
诸小亮:如果使用 List 特有迭代器就没问题
结果:
3. ArrayList
诸小亮:接下来我们介绍ArrayList——最常使用的列表容器
张小飞:看名字就知道,它的底层是数组结构
1. 可变数组
诸小亮:不错,它最大的特点就是——底层是可变数组
张小飞:数组有默认长度吧
诸小亮:是的,创建 ArrayList 对象时,其数组的默认长度是10
张小飞:我记得用可变数组——就是在数组存满后会创建一个新的更大的数组?
诸小亮:你说的不错,因此从指定位置插入和删除元素时候,要移动后面的所有元素,导致速度较慢
张小飞:既然这么慢,为什么您说 ArrayList 是最常用的列表容器呢?
诸小亮:因为它通过下标获取元素的速度非常块,工作中大多数都是读,而不是写
张小飞:明白了
诸小亮,还有一点,因为是可变数组,所以会自动扩容
张小飞:嗯嗯,这个我明白
诸小亮:重点是——扩容就是创建一个新的数组,是原来数组长度的 1.5 倍
2. 多线程
诸小亮:需要注意,ArrayList方法不是同步的,所以多线程操作是不安全的
张小飞:明白,就是跟 StringBuilder 差不多
诸小亮,额。。。,是有些类似
3. 存储重复元素
诸小亮:另外, List 是可以存储重复元素的
结果:
张小飞:难道还有其他的不能存储重复元素?
诸小亮:是的,我们之后会讲到
4. 操作自定义对象
诸小亮:之前操作的都是一些基本类型对象,下面我们操作自定义对象,比如:
class Hero {
String name;
) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class StringDemo {
public static void main(String[] args) throws Exception {
ArrayList list = new ArrayList();
//1. 存储自定义对象
list.add(new Hero("西施"));
list.add(new Hero("嫦娥"));
list.add(new Hero("甄姬"));
//2. 循环获取每个对象
for(int i =0;i<list.size();i++){
Hero hero = (Hero) list.get(i);//默认获取的是Object类型,需要向下转型
System.out.println(hero.getName());
}
}
}
结果:
诸小亮,另外,获取元素时,也可以使用增强 for 循环
张小飞:操作自定义对象跟操作其他对象,没什么区别啊
诸小亮:是的
张小飞:那为什么要单独举个例子呢?
诸小亮:因为我们下面会用到
5. 去除重复元素
诸小亮:因为 ArrayList 可以存储重复元素,所以去重是工作中非常常见的场景
张小飞:这还不简单,它不是有个 contains 方法吗?用这个方法就可以了判断是否有重复元素了
class Hero {
String name;
public Hero(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//复写 equals 方法,判断两个Hero对象是否一样
public boolean equals(Object obj){
if(obj instanceof Hero){
// 如果 name 一样,就认为 两个 hero 对象相同
return this.getName().equals(((Hero)obj).getName());
}
return false;
}
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
'}';
}
}
public class StringDemo {
public static void main(String[] args) throws Exception {
ArrayList list = new ArrayList();
list.add(new Hero("西施"));
list.add(new Hero("妲己"));
list.add(new Hero("嫦娥"));
list.add(new Hero("甄姬"));
list.add(new Hero("女娲"));
list.add(new Hero("芈月"));
list.add(new Hero("妲己"));
list.add(new Hero("甄姬"));
//去重
getSingelElement(list);
System.out.println(list);
}
private static void getSingelElement(ArrayList list) {
//1. 创建一个新的列表存储不重复的元素
ArrayList newList = new ArrayList();
newList.add(list.get(0));
for (int i = 1; i < list.size(); i++) {
//2. 判断newList是否包含指定元素,如果不包含就存起来
Hero hero = (Hero) list.get(i);
if(newList.contains(hero)){
//contains内部会调用元素的equals方法,判断你是否一样,所以Hero中要定义equals方法
continue;
}
newList.add(hero);
}
list.clear();//清空老的数据
list.addAll(newList);//放入新的数据
}
}
诸小亮:不错,没想到你还真是考虑到在 Hero 中复写 equals 方法了
张小飞:嘿嘿,您之前不是说过嘛,contains 的内部就是调用了元素的 equals 方法
4. LinkedList
诸小亮:接着,我们说LinkedList——也是 List 接口的具体实现类之一,但工作中使用不是很多
1. 链表
张小飞:LinkedList 底层也是用的数组吗?
诸小亮:非也,LinkedList 底层使用的是链表
- 链表是一种数据结构:前面节点存储着下一个节点的地址,比如:
张小飞:这么说,只要拿到第一个节点,就能获取之后的所有节点了,
诸小亮:不错,不过这只是:单向链表,而 LinkedList 底层是双向链表
张小飞:什么是双向链表?
诸小亮:来,看下面这个图
张小飞:明白了,就是每个元素不仅存放着下一个元素的地址,也存放着前一个元素的地址
诸小亮:没错,因为这种特性所以链表在插入和删除的时候,效率很高,比如:
张小飞:嗯嗯,确实,插入时只需要修改 next 属性就行了
张小飞:不过,LinkedList 的 get() 方法效率应该很慢比 ArrayList 慢吧
诸小亮:是的,比如 get(5),就意味着从头节点开始不断的向后找5次,才能获取到对应的数据
诸小亮:另外,链表跟数组最大的区别:数组在内存中是一块儿连续的内存,链表不是
张小飞:明白
诸小亮:LinkedList 还有一些其他特点,作为了解
- 可以存储重复元素
- 多线程下也是不安全的
2. 特有方法
诸小亮:LinkedList 也有一些自己特有的方法
1. addFirst
addFirst:把元素当成头节点加入链表中
public static void main(String[] args) throws Exception {
LinkedList list = new LinkedList();
list.add(new Hero("西施"));
list.add(new Hero("妲己"));
list.addFirst(new Hero("嫦娥"));//把 嫦娥 作为头节点
System.out.println(list.getFirst());//获取头节点
}
结果:
2. removeFirst
removeFirst:删除头节点,并返回头节点元素
结果:
3. 遍历
诸小亮:因为 get(int index) 方法的效率很差,所以不推荐使用一般的 for 循环
张小飞:那,使用 Iterator 吗?
诸小亮:no,no,no,可以用 增强 for 循环
张小飞:这是为什么呢?
诸小亮:使用普通 for 循环就是根据下标获取元素,之前已经说了,效率很慢
张小飞:使用增强 for 循环就快了?
诸小亮:是的,而使用增强 for 循环不需要下标,而且更加简洁、易读
张小飞:明白了
诸小亮:但是,增强 for 循环在遍历时,无法对容器进行修改操作否则报错,你可以尝试一下
5. Vector
张小飞:这个 Vector 是???
诸小亮:Vector 是最早的一个集合类,底层也是可变数组
张小飞:这不是跟 ArrayList 一样吗?
诸小亮:非也,Vector 中都是同步方法,所以 ArrayList 是它的替代品
张小飞:原来如此
相关推荐
- Go语言泛型-泛型约束与实践(go1.7泛型)
-
来源:械说在Go语言中,Go泛型-泛型约束与实践部分主要探讨如何定义和使用泛型约束(Constraints),以及如何在实际开发中利用泛型进行更灵活的编程。以下是详细内容:一、什么是泛型约束?**泛型...
- golang总结(golang实战教程)
-
基础部分Go语言有哪些优势?1简单易学:语法简洁,减少了代码的冗余。高效并发:内置强大的goroutine和channel,使并发编程更加高效且易于管理。内存管理:拥有自动垃圾回收机制,减少内...
- Go 官宣:新版 Protobuf API(go pro版本)
-
原文作者:JoeTsai,DamienNeil和HerbieOng原文链接:https://blog.golang.org/a-new-go-api-for-protocol-buffer...
- Golang开发的一些注意事项(一)(golang入门项目)
-
1.channel关闭后读的问题当channel关闭之后再去读取它,虽然不会引发panic,但会直接得到零值,而且ok的值为false。packagemainimport"...
- golang 托盘菜单应用及打开系统默认浏览器
-
之前看到一个应用,用go语言编写,说是某某程序的windows图形化客户端,体验一下发现只是一个托盘,然后托盘菜单的控制面板功能直接打开本地浏览器访问程序启动的webserver网页完成gui相关功...
- golang标准库每日一库之 io/ioutil
-
一、核心函数概览函数作用描述替代方案(Go1.16+)ioutil.ReadFile(filename)一次性读取整个文件内容(返回[]byte)os.ReadFileioutil.WriteFi...
- 文件类型更改器——GoLang 中的 CLI 工具
-
我是如何为一项琐碎的工作任务创建一个简单的工具的,你也可以上周我开始玩GoLang,它是一种由Google制作的类C编译语言,非常轻量和快速,事实上它经常在Techempower的基准测...
- Go (Golang) 中的 Channels 简介(golang channel长度和容量)
-
这篇文章重点介绍Channels(通道)在Go中的工作方式,以及如何在代码中使用它们。在Go中,Channels是一种编程结构,它允许我们在代码的不同部分之间移动数据,通常来自不同的goro...
- Golang引入泛型:Go将Interface「」替换为“Any”
-
现在Go将拥有泛型:Go将Interface{}替换为“Any”,这是一个类型别名:typeany=interface{}这会引入了泛型作好准备,实际上,带有泛型的Go1.18Beta...
- 一文带你看懂Golang最新特性(golang2.0特性)
-
作者:腾讯PCG代码委员会经过十余年的迭代,Go语言逐渐成为云计算时代主流的编程语言。下到云计算基础设施,上到微服务,越来越多的流行产品使用Go语言编写。可见其影响力已经非常强大。一、Go语言发展历史...
- Go 每日一库之 java 转 go 遇到 Apollo?让 agollo 来平滑迁移
-
以下文章来源于GoOfficialBlog,作者GoOfficialBlogIntroductionagollo是Apollo的Golang客户端Apollo(阿波罗)是携程框架部门研...
- Golang使用grpc详解(golang gcc)
-
gRPC是Google开源的一种高性能、跨语言的远程过程调用(RPC)框架,它使用ProtocolBuffers作为序列化工具,支持多种编程语言,如C++,Java,Python,Go等。gR...
- Etcd服务注册与发现封装实现--golang
-
服务注册register.gopackageregisterimport("fmt""time"etcd3"github.com/cor...
- Golang:将日志以Json格式输出到Kafka
-
在上一篇文章中我实现了一个支持Debug、Info、Error等多个级别的日志库,并将日志写到了磁盘文件中,代码比较简单,适合练手。有兴趣的可以通过这个链接前往:https://github.com/...
- 如何从 PHP 过渡到 Golang?(php转golang)
-
我是PHP开发者,转Go两个月了吧,记录一下使用Golang怎么一步步开发新项目。本着有坑填坑,有错改错的宗旨,从零开始,开始学习。因为我司没有专门的Golang大牛,所以我也只能一步步自己去...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- libcrypto.so (74)
- linux安装minio (74)
- ubuntuunzip (67)
- vscode使用技巧 (83)
- secure-file-priv (67)
- vue阻止冒泡 (67)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)