Java集合框架之List ArrayList LinkedList使用详解刨析
作者:谢谢你,泰罗! 发布时间:2022-04-24 13:43:43
1. List
1.1 List 的常见方法
方法 | 描述 |
---|---|
boolean add(E e) | 尾插 e |
void add(int index, E element) | 将 e 插入到 index 位置 |
boolean addAll(Collection<? extends E> c) | 尾插 c 中的元素 |
E remove(int index) | 删除 index 位置的元素 |
boolean remove(Object o) | 删除遇到的第一个 o |
E get(int index) | 获取下标 index 位置的元素 |
E set(int index, E element) | 将下标 index 位置元素设置为 element |
void clear() | 清空 |
boolean contains(Object o) | 判断 o 是否在线性表中 |
int indexOf(Object o) | 返回第一个 o 所在下标 |
int lastIndexOf(Object o) | 返回最后一个 o 的下标 |
List<E> subList(int fromIndex, int toIndex) | 截取部分 list |
1.2 代码示例
注意: 下面的示例都是一份代码分开拿出来的,上下其实是有逻辑关系的
示例一: 用 List 构造一个元素为整形的顺序表
List<Integer> list = new ArrayList<>();
示例二: 尾插 e
list.add(1);
list.add(2);
System.out.println(list);
// 结果为:[1, 2]
示例三: 将 e 插入到 index 位置
list.add(0,10);
System.out.println(list);
// 结果为:[10, 1, 2]
示例四: 尾插 c 中的元素
List<Integer> list1=new LinkedList<>();
list1.add(99);
list1.add(100);
list.addAll(list1);
System.out.println(list);
// 结果为:[10, 1, 2, 99, 100]
只要是继承于 Collection 的集合类的元素都可以 * 入进去,但要注意传过来的具体的类型要么是和 list 的具体类型是一样的,要么是 list 具体类型的子类
示例五: 删除 index 位置的元素
System.out.println(list.remove(0));
System.out.println(list);
// 结果为:10 和 [1, 2, 99, 100]
示例六: 删除遇到的第一个 o
System.out.println(list.remove((Integer) 100));
System.out.println(list);
// 结果为:true 和 [1, 2, 99]
示例七: 获取下标 index 位置的元素
System.out.println(list.get(0));
// 结果为:1
示例八: 将下标 index 位置元素设置为 element
System.out.println(list.set(2,3));
System.out.println(list);
// 结果为:99 和 [1, 2, 3]
示例九: 判断 o 是否在线性表中
System.out.println(list.contains(1));
// 结果为:true
示例十: 返回第一个 o 所在下标
System.out.println(list.indexOf(1));
// 结果为:0
示例十一: 返回最后一个 o 的下标
list.add(1);
System.out.println(list.lastIndexOf(1));
// 结果为:3
示例十二: 截取部分 list
List<Integer> list2=list.subList(1,3);
System.out.println(list2);
// 结果为:[2, 3]
注意,当我们将 list2 通过 set 更改元素,其实对 list 也会有影响
list2.set(0,5);
System.out.println(list2);
System.out.println(list);
// 结果为:[5, 3] 和 [1, 5, 3, 1]
通过 subList 方法进行的截取,得到的集合的数值指向的地址和原集合中数值的地址是一样的
2. ArrayList
2.1 介绍
ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。其继承了 AbstractList,并实现了 List 接口。LinkedList 不仅实现了 List 接口,还实现了 Queue 和 Deque 接口,可以作为队列去使用。
ArrayList 类位于 java.util
包中,使用前需要引入它。
2.2 ArrayList 的构造方法
方法 | 描述 |
---|---|
ArrayList() | 无参构造 |
ArrayList(Collection<? extends E> c) | 利用其他 Collection 构建 ArrayList |
ArrayList(int initialCapacity) | 指定顺序表初始容量 |
示例一:
ArrayList<Integer> list1 = new ArrayList<>();
示例二:
ArrayList<Integer> list2 = new ArrayList<>(10);
// 该构造方法就是在构建时就将底层数组大小设置为了10
示例三:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
ArrayList<Integer> list3 = new ArrayList<>(list);
Collection<? extends E> c
只要是具体类型都和 list3 是一样的集合都可以放入转化成 ArrayList
2.3 ArrayList 底层数组的大小
当我们使用 add 方法给 ArrayList 的对象进行尾插时,突然想到了一个问题:既然 ArrayList 的底层是一个数组,那么这个数组有多大呢?
为了解决这个问题,我进行了如下探索
跳转到 ArrayList 的定义,我们看到了 elementData
和 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
跳转到 elementData
的定义,我们可以了解 ArrayList 底层是数组的原因
跳转到 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
的定义,初步分析得到这个数组其实是空的
为什么这个数组是空的但存储元素的时候没有报异常呢?我们再去了解下 add 是怎样存储的
通过转到 ArrayList 的 add 方法的定义
通过定义,不难发现,数组容量和 ensureCapacityInternal
这个东西有关,那我们就看看它的定义
我们看里面的 calculateCapacity
,他有两个参数,此时数组为空,那么 minCapacity
就为 1。我们再转到 calculateCapacity
看看它的定义
此时我们就好像可以与之前串起来了,当数组为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
时,就返回 DeFauLt_CAPACITY
和 minCapacity
(此时为1) 的最大值。DeFauLt_CAPACITY
其实是默认容量的意思,我们可以转到它的定义看看有多大
DeFauLt_CAPACITY
的值是10,故 calculateCapacity
函数此时的返回值为10,最后我们再确定一下 ensureExplicitCapacity
是干啥的
此时 minCapacity 的值是10,而数组为空时数组长度为0,所以进入 if 语句,执行 grow 方法,我们继续转到 grow 的定义
此时我们就可以了解,当我们创建一个 ArrayList 时,其底层数组大小其实是0。当我们第一次 add 的时候,经过 grow ,数组的大小就被扩容为了10。并且这大小为10的容量放满以后,就会按1.5倍的大小继续扩容。至于这个数组最大能存放多少,大家可以再转到 MAX_ARRAY_SIZE
的定义去查看。
3. LinkedList
3.1 介绍
LinkedList 类是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址。
Java 的 LinkedList 底层是一个双向链表,位于 java.util
包中,使用前需要引入它
3.2 LinkedList 的构造方法
方法 | 描述 |
---|---|
LinkedList() | 无参构造 |
LinkedList(Collection<? extends E> c) | 利用其他 Collection 构建 LinkedList |
示例一:
LinkedList<Integer> list1 = new LinkedList<>();
示例二:
List<Integer> list = new LinkedList<>();
list.add(1);
list.add(2);
LinkedList<Integer> list2 = new LinkedList<>(list);
Collection<? extends E> c
只要是具体类型都和 list2 是一样的集合都可以放入转化成 LinkedList
4. 练习题
习题一
题目描述:
霍格沃茨学院有若干学生(学生对象放在一个 List 中),每个学生有一个姓名(String)、班级(String)和考试成绩(double)。某次考试结束后,每个学生都获得了一个考试成绩。遍历 list 集合,并把每个学生对象的属性都打印出来
本题代码:
class Student{
private String name;
private String classes;
private double score;
// 重写构造方法
public Student(String name, String classes, double score) {
this.name = name;
this.classes = classes;
this.score = score;
}
// 构造 get 和 set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClasses() {
return classes;
}
public void setClasses(String classes) {
this.classes = classes;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
// 重写 toString 方法
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", classes='" + classes + '\'' +
", score=" + score +
'}';
}
}
public class TestDemo {
public static void main(String[] args) {
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("哈利波特","大二班",95.5));
students.add(new Student("赫敏格兰杰","小三班",93));
students.add(new Student("罗恩韦斯莱","小二班",91));
for(Student s: students){
System.out.println(s);
}
}
}
// 结果为:
// Student{name='哈利波特', classes='大二班', score=95.5}
// Student{name='赫敏格兰杰', classes='小三班', score=93.0}
// Student{name='罗恩韦斯莱', classes='小二班', score=91.0}
习题二
题目描述:
有一个 List 当中存放的是整形的数据,要求使用 Collections.sort
对 List 进行排序
该题代码:
public class TestDemo {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(3);
list.add(7);
list.add(1);
list.add(6);
list.add(2);
Collections.sort(list);
System.out.println(list);
}
}
// 结果为:[1, 2, 3, 6, 7]
补充:
Collections 是一个工具类,sort 是其中的静态方法,它是用来对 List 类型进行排序的
注意:
如果具体的类是类似于习题一那样的 Student 类,该类中含有多个属性,那就不能直接使用这个方法。要对 comparator
或者 comparable
接口进行重写,确定比较的是哪个属性才行
习题三
题目描述:
输出删除了第一个字符串当中出现的第二个字符串中的字符的字符串,例如
String str1 = "welcome to harrypotter";
String str2 = "come";
// 结果为:wl t harrypttr
希望本题可以使用集合来解决
该题代码:
public static void removeS(String str1, String str2){
if(str1==null || str2==null){
return;
}
List<Character> list = new ArrayList<>();
int lenStr1=str1.length();
for(int i=0; i<lenStr1; i++){
char c = str1.charAt(i);
if(!str2.contains(c+"")){
list.add(c);
}
}
for(char ch: list){
System.out.print(ch);
}
}
5. 扑克牌小游戏
我们可以通过上述所学,运用 List 的知识,去写一个关于扑克牌的逻辑代码(如:获取一副牌、洗牌、发牌等等)
class Card{
private String suit; // 花色
private int rank; // 牌面值
public Card(String suit, int rank){
this.suit=suit;
this.rank=rank;
}
@Override
public String toString() {
return "[ "+suit+" "+rank+" ] ";
}
}
public class TestDemo {
public static String[] suits = {"♣", "♦", "♥", "♠"};
// 获取一副牌
public static List<Card> getNewCards(){
// 存放 52 张牌
List<Card> card = new ArrayList<>();
for(int i=0; i<4; i++){
for(int j=1; j<=13; j++) {
card.add(new Card(suits[i], j));
}
}
return card;
}
public static void swap(List<Card> card, int i, int j){
Card tmp = card.get(i);
card.set(i, card.get(j));
card.set(j, tmp);
}
// 洗牌
public static void shuffle(List<Card> card){
int size = card.size();
for(int i=size-1; i>0; i--){
Random random = new Random();
int randNum = random.nextInt(i);
swap(card, i, randNum);
}
}
public static void main(String[] args) {
// 得到一副新的牌
List<Card> cardList = getNewCards();
System.out.println("已获取新的扑克牌");
System.out.println("洗牌:");
shuffle(cardList);
System.out.println(cardList);
System.out.println("抓牌:(3个人,每人轮流抓牌总共抓5张)");
List<Card> hand1 = new ArrayList<>();
List<Card> hand2 = new ArrayList<>();
List<Card> hand3 = new ArrayList<>();
List<List<Card>> hands = new ArrayList<>();
hands.add(hand1);
hands.add(hand2);
hands.add(hand3);
for(int i=0; i<5; i++){
for(int j=0; j<3; j++){
Card card = cardList.remove(0);
hands.get(j).add(card);
}
}
System.out.println("第一个人的牌:"+hand1);
System.out.println("第二个人的牌:"+hand2);
System.out.println("第三个人的牌:"+hand3);
}
}
/**
结果为:
已获取新的扑克牌
洗牌:
[[ ♥ 9 ] , [ ♦ 6 ] , [ ♣ 8 ] , [ ♦ 2 ] , [ ♣ 6 ] , [ ♦ 4 ] , [ ♣ 11 ] , [ ♣ 9 ] , [ ♠ 8 ] , [ ♣ 5 ] , [ ♦ 8 ] , [ ♦ 10 ] , [ ♦ 1 ] , [ ♦ 12 ] , [ ♥ 10 ] , [ ♥ 7 ] , [ ♠ 12 ] , [ ♥ 12 ] , [ ♦ 7 ] , [ ♣ 13 ] , [ ♠ 6 ] , [ ♠ 5 ] , [ ♥ 3 ] , [ ♦ 5 ] , [ ♦ 11 ] , [ ♣ 12 ] , [ ♠ 7 ] , [ ♦ 3 ] , [ ♥ 5 ] , [ ♦ 13 ] , [ ♣ 1 ] , [ ♥ 8 ] , [ ♠ 10 ] , [ ♠ 4 ] , [ ♣ 4 ] , [ ♣ 7 ] , [ ♥ 1 ] , [ ♠ 1 ] , [ ♣ 3 ] , [ ♥ 11 ] , [ ♥ 13 ] , [ ♦ 9 ] , [ ♠ 13 ] , [ ♣ 10 ] , [ ♥ 6 ] , [ ♠ 11 ] , [ ♠ 3 ] , [ ♣ 2 ] , [ ♠ 2 ] , [ ♥ 2 ] , [ ♥ 4 ] , [ ♠ 9 ] ]
抓牌:(3个人,每人轮流抓牌总共抓5张)
第一个人的牌:[[ ♥ 9 ] , [ ♦ 2 ] , [ ♣ 11 ] , [ ♣ 5 ] , [ ♦ 1 ] ]
第二个人的牌:[[ ♦ 6 ] , [ ♣ 6 ] , [ ♣ 9 ] , [ ♦ 8 ] , [ ♦ 12 ] ]
第三个人的牌:[[ ♣ 8 ] , [ ♦ 4 ] , [ ♠ 8 ] , [ ♦ 10 ] , [ ♥ 10 ] ]
*/
上述代码中有一处代码是这样写的 List<List<Card>>
,其实不难理解,这个类型其实就是 List 中存放的每个元素都是一个 List 类型的,并且每一个 List 元素中的元素都是 Card 类型,类似于二维数组。
来源:https://blog.csdn.net/weixin_51367845/article/details/120838319
猜你喜欢
- 摘要:其实两种方法归结起来看还是一种,都是利用Thread的构造器进行创建,区别就是一种是无参的,一种是有参的。一、继承Thread线程类:
- 一、遇到一个问题1、读取CSV文件package com.guor.demo.charset;import java.io.Buffered
- 我就废话不多说了,大家还是直接看代码吧~<select id="getBiTree" parameterType=
- 为什么要重复造轮子你可能会问,Spring已经自带了全局异常拦截,为什么还要重复造轮子呢?这是个好问题,我觉得有以下几个原因装逼Spring
- java 泛型方法:泛型是什么意思在这就不多说了,而Java中泛型类的定义也比较简单,例如:public class Test
- 前言春节要到了,看惯了前端各种小游戏,确实做得很好,很精致。但是我也要为后端程序员稍微做一点贡献,做一款java版本的【年兽大作战】。这个游
- 网上很多资料在描述Java内存模型的时候,都会介绍有一个主存,然后每个工作线程有自己的工作内存。数据在主存中会有一份,在工作内存中也有一份。
- 什么是RecyclerView关于RecyclerView,是一个主要用于展示和回收View的有一个控件,在官用了一句话来概括Recycle
- 微服务feign调用添加token1.一般情况是这么配置的具体的怎么调用就不说了 如下配置,就可以在请求头中添加需要的请求头信息。packa
- 效果展示人脸支付效果视频密码框输入支付效果视频因为密码支付时会调起系统安全键盘,开启自动保护功能,防止泄露,会导致输入密码时录屏黑屏,故使用
- 本文实例为大家分享了java微信公众号支付示例代码,供大家参考,具体内容如下开始之前,先准备好:appid、商家号、商户密匙。工具类:MD5
- 一、简介ThreadPool相比Thread来说具备了很多优势,但是ThreadPool却又存在一些使用上的不方便。比如:Task支持线程的
- 正在尝试分配更低的访问权限?在进行Java编程时会给我们报出如下提示怎么办?这里我们将给大家介绍详细的解决方法。首先,查看,控制台给出的提示
- 1 前言许多语言,例如 Perl ,Python 和 Ruby ,都有集合的本地支持。有些语言(例如Python)甚至将基本集合组件(列表,
- 使用过 mybatis 框架的小伙伴们都知道,mybatis 是个半 orm 框架,通过写 mapper 接口就能自动实现数据库的增删改查,
- 1.editplus1.1 官方下载https://www.editplus.com/官方下载最新的64位2 .解压就可以使用2.1 vsc
- 1、错误的解决方案1.1、 先更新数据库,再删除缓存若数据库更新成功,删除缓存操作失败,则此后读到的都是缓存中过期的数据,造成不一致问题。1
- 最近碰到这么个恶心的问题问题:有个arr文件被放到Module A中引用,现在Module B又依赖了Module A,则在编译过程中会发生
- 为了让我提供的通用 Mapper 的 boot-starter 同时兼容 Spring Boot 1.x 和 2.x,增加了这么一个工具类。
- 1、静态代码块①、格式在java类中(方法中不能存在静态代码块)使用static关键字和{}声明的代码块:public class Code