Java—List集合详解
关注微信公众号:CodingTechWork,一起学习进步。
List集合介绍
List集合概述
List集合是一个元素有序(每个元素都有对应的顺序索引,第一个元素索引为0)、且可重复的集合。
List集合常用方法
List是Collection接口的子接口,拥有Collection所有方法外,还有一些对索引操作的方法。
void add(int index, E element);
:将元素element插入到List集合的index处;boolean addAll(int index, Collection<? extends E> c);
:将集合c所有的元素都插入到List集合的index起始处;E remove(int index);
:移除并返回index处的元素;int indexOf(Object o);
:返回对象o在List集合中第一次出现的位置索引;int lastIndexOf(Object o);
:返回对象o在List集合中最后一次出现的位置索引;E set(int index, E element);
:将index索引处的元素替换为新的element对象,并返回被替换的旧元素
;E get(int index);
:返回集合index索引处的对象;List<E> subList(int fromIndex, int toIndex);
:返回从索引fromIndex(包含)到索引toIndex(不包含)所有元素组成的子集合;void sort(Comparator<? super E> c)
:根据Comparator参数对List集合元素进行排序;void replaceAll(UnaryOperator<E> operator)
:根据operator指定的计算规则重新设置集合的所有元素。ListIterator<E> listIterator();
:返回一个ListIterator对象,该接口继承了Iterator接口,在Iterator接口基础上增加了以下方法,具有向前迭代功能且可以增加元素:
bookean hasPrevious()
:返回迭代器关联的集合是否还有上一个元素;
E previous();
:返回迭代器上一个元素;
void add(E e);
:在指定位置插入元素;
示例
1)运行主类
public class DemoApplication {public static void main(String[] args) {List<String> list = new ArrayList();list.add(new String("book001"));list.add(new String("book002"));list.add(new String(" book003 "));System.out.println("原列表:" + list);//将新字符串插入第二个位置list.add(1, new String("newBook002"));System.out.println("新增第二个位置元素后列表:" + list);//删除第三个元素list.remove(2);System.out.println("删除第三个元素后列表:" + list);//判断指定元素在List集合的位置System.out.println("判断newBook002的位置:" + list.indexOf(new String("newBook002")));//将第二元素替换新的字符串System.out.println("替换的旧值:" + list.set(1, new String("book002")));System.out.println("替换第二个元素后的列表:" + list);//返回第二个元素System.out.println("回第二个元素:" + list.get(1));List<String> newList = new ArrayList<>();newList.add("book001");newList.add("book004");newList.add("book002");//新增集合list.addAll(1, newList);System.out.println("新增一个集合后的列表:" + list);//返回元素最后一次出现的位置索引System.out.println("返回\"book001\"最后一次出现的位置:" + list.lastIndexOf("book001"));//截取子集合System.out.println("返回一个范围子集合列表:" + list.subList(0, 3));list.sort(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {//逆序return o2.compareTo(o1);}});//lambda表达式输出list.forEach(book -> System.out.println(book));list.replaceAll(String::trim);System.out.println("replaceAll去除两端空格" + list);list.replaceAll(t -> t.replace("book00", "书籍系列"));System.out.println("replaceAll替换字符串:" + list);System.out.println("正向迭代输出:");ListIterator listIterator = list.listIterator();while (listIterator.hasNext()) {System.out.println(listIterator.next());//添加元素,会影响list元素listIterator.add("book");}System.out.println("反向迭代输出:");while(listIterator.hasPrevious()) {System.out.println(listIterator.previous());}System.out.println(list);}}
2)运行结果:
原列表:[book001, book002, book003 ]
新增第二个位置元素后列表:[book001, newBook002, book002, book003 ]
删除第三个元素后列表:[book001, newBook002, book003 ]
判断newBook002的位置:1
替换的旧值:newBook002
替换第二个元素后的列表:[book001, book002, book003 ]
回第二个元素:book002
新增一个集合后的列表:[book001, book001, book004, book002, book002, book003 ]
返回"book001"最后一次出现的位置:1
返回一个范围子集合列表:[book001, book001, book004]
book004
book002
book002
book001
book001book003
replaceAll去除两端空格[book004, book002, book002, book001, book001, book003]
replaceAll替换字符串:[书籍系列4, 书籍系列2, 书籍系列2, 书籍系列1, 书籍系列1, 书籍系列3]
正向迭代输出:
书籍系列4
书籍系列2
书籍系列2
书籍系列1
书籍系列1
书籍系列3
反向迭代输出:
book
书籍系列3
book
书籍系列1
book
书籍系列1
book
书籍系列2
book
书籍系列2
book
书籍系列4
[书籍系列4, book, 书籍系列2, book, 书籍系列2, book, 书籍系列1, book, 书籍系列1, book, 书籍系列3, book]
从上述运行结果看出,System.out.println("判断newBook002的位置:" + list.indexOf(new String("newBook002")));
我们重新new一个"newBook002"进行判断索引位置时,还是可以返回索引位置,List集合判断两个对象相当只通过equals()
方法,所以如果重写对象的equals()
方法都是true,则存入List集合中的对象其实都是相等的。
ArrayList
ArrayList概述
ArrayList 是一个数组队列,相当于动态数组。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List
, RandomAccess
(随机访问), Cloneable
(克隆), java.io.Serializable
(可序列化)这些接口。
ArrayList 继承了AbstractList
,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
ArrayList 实现了RandmoAccess
接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问
。
ArrayList 实现了Cloneable
接口,即覆盖了函数clone()
,能被克隆。
ArrayList 实现java.io.Serializable
接口,这意味着ArrayList支持序列化
,能通过序列化去传输。
和Vector不同,ArrayList中的操作不是线程安全
的!所以,建议在单线程
中才使用ArrayList
,而在多线程
中可以选择Vector
或者CopyOnWriteArrayList
。
ArrayList源码解析
- ArrayList包含了两个重要的对象:
elementData
和size
。
elementData
是"Object[]类型的数组",它保存了添加到ArrayList中的元素。实际上,elementData是个动态数组,我们能通过构造函数 ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity;如果通过不含参数的构造函数ArrayList()来创建ArrayList,则elementData的容量默认是10。elementData数组的大小会根据ArrayList容量的增长而动态的增长
size
则是动态数组的实际大小。
// 默认初始化容量为10/** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10;// DEFAULTCAPACITY_EMPTY_ELEMENTDATA默认为空数组/*** Shared empty array instance used for default sized empty instances. We* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when* first element is added.*/private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};// 才开始构造的时候是一个空list,只有当第一个元素add的时候,扩展到DEFAULT_CAPACITY值,即长度为10./** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. */ transient Object[] elementData; // non-private to simplify nested class access// 构造成10长度的空list; /** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
- ArrayList 实际上是通过一个数组去保存数据的。当我们构造ArrayList时;若使用默认构造函数,则ArrayList的默认容量大小是
10
。 - 当ArrayList容量不足以容纳全部元素时,ArrayList会重新设置容量:
新的容量=“(原始容量x3)/2 + 1
”。 - ArrayList的克隆函数,即是将全部元素克隆到一个数组中。
- ArrayList实现
java.io.Serializable
的方式。当写入到输出流时,先写入“容量”,再依次写入“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
ArrayList的遍历方式
3种方式
- 第一种,通过迭代器遍历。即通过
Iterator
去遍历。
Integer value = null;
Iterator iter = list.iterator();
while (iter.hasNext()) {value = (Integer)iter.next();
}
- 第二种,
随机访问index
,通过索引值去遍历。
由于ArrayList实现了RandomAccess接口,它支持通过索引值去随机访问元素。
Integer value = null;
int size = list.size();
for (int i=0; i<size; i++) {value = (Integer)list.get(i);
}
- 第三种,
增强for循环遍历
。如下:
Integer value = null;
for (Integer integ:list) {value = integ;
}
遍历ArrayList时,使用随机访问(即,通过索引序号访问)效率最高,而使用迭代器的效率最低
LinkedList
LinkedList概述
LinkedList 是一个继承于AbstractSequentialList
的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。LinkedList的本质是双向链表。1)LinkedList继承于AbstractSequentialList,并且实现了Dequeue接口。2) LinkedList包含两个重要的成员:header 和 size。
header
是双向链表的表头,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量:previous, next, element。(其中,previous
是该节点的上一个节点,next
是该节点的下一个节点,element
是该节点所包含的值。)
size
是双向链表中节点的个数。
LinkedList 实现List接口
,能对它进行队列操作。
LinkedList 实现 Deque接口
,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口
,即覆盖了函数clone()
,能克隆。
LinkedList 实现java.io.Serializable接口
,这意味着LinkedList支持序列化
,能通过序列化去传输。
LinkedList 是非同步的
。(若要实现同步 List list = Collections.synchronizedList(new LinkedList(...))
;)
LinkedList源码分析
- 访问性
LinkedList实际上是通过双向链表
去实现的。既然是双向链表,那么它的顺序访问会非常高效
,而随机访问效率比较低
。 - 根据索引值操作
既然LinkedList是通过双向链表的,但是它也实现了List接口,也就是说,它实现了get(int index)
、remove(int index)
等根据索引值来获取、删除节点的函数。 - LinkedList是如何实现List的这些接口的,如何将双向链表和索引值联系起来的?其实,它是通过一个
计数索引值
来实现的。例如,当程序调用get(int index)
方法时,首先会比较location
和双向链表长度的1/2
;如果前者大,则从链表头开始向后
查找,直到location位置
;否则,从链表末尾开始向前
查找,直到location位置
。
总结:
- LinkedList 实际上是通过
双向链表
去实现的。包含一个非常重要的内部类:Entry
。Entry是双向链表节点所对应的数据结构,它包括的属性有:当前节点所包含的值
,上一个节点
,下一个节点
。 - LinkedList的克隆函数,即是将全部元素克隆到一个新的LinkedList对象中。
- LinkedList实现
java.io.Serializable
。当写入到输出流时,先写入“容量”,再依次写入“每一个节点保护的值”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。 - 由于LinkedList实现了
Deque
,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。
LinkedList遍历方式
支持多种遍历方式。建议不要采用随机访问的方式去遍历LinkedList,而采用逐个遍历的方式。
- 第一种,通过迭代器遍历。即通过
Iterator
去遍历。
for(Iterator iter = list.iterator(); iter.hasNext();)iter.next();
- 通过
快速随机index
访问遍历LinkedList
int size = list.size();
for (int i=0; i<size; i++) {list.get(i);
}
- 通过另外一种
增强版for循环
来遍历LinkedList
for (Integer ele: list) {}
- 通过
pollFirst()
来遍历LinkedList,获取并移除此列表的第一个元素
;如果此列表为空,则返回 null
while(list.pollFirst() != null){}
- 通过
pollLast()
来遍历LinkedList,获取并移除此列表的最后一个元素
;如果此列表为空,则返回 null。
while(list.pollLast() != null) {}
- 通过
removeFirst()
来遍历LinkedList,移除并返回此列表的第一个元素
。 NoSuchElementException - 如果此列表为空。
try {while(list.removeFirst() != null) {}
} catch (NoSuchElementException e) {}
- 通过
removeLast()
来遍历LinkedList,移除并返回此列表的最后一个元素
。NoSuchElementException - 如果此列表为空。
try {while(list.removeLast() != null) {}
} catch (NoSuchElementException e) {}
QA
ArrayList底层动态扩容的原理?
ArrayList底层采用数组实现,当使用不带参数的构造方法生成ArrayList对象时,底层实际会生成一个长度为10
的Object类型数组
,如果增加的元素个数超过10个,则ArrayList底层会新生成一个数组,长度为原数组的1.5倍+1
,然后将原数组的内容复制到新数组中去,兵器后续增加的内容都会放入新数组中,当新数组无法容纳新元素时,又会重复上述步骤。
ArrayList和LinkedList的区别?
- 底层实现:ArrayList实现是基于动态数组的数据结构(新建一个数组进行扩容,然后copy原来数组中内容,实现数组可增长);LinkedList是基于双向链表的数据结构,其每个对象除了数据本身外,还有两个引用,分别指向前一个元素和后一个元素。
- 查询:对于随机访问get和set,ArrayList支持;LinkedList不支持,因为LinkedList要移动指针。
- 增删:对于新增和删除操作add和remove,在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。
- 应用场景:ArrayList适合一列数据的后面添加数据而不是在前面或中间,且需要随机访问元素;LinkedList适合在一列数据的前面或中间添加或删除数据,且按照顺序访问其中的元素。
- 消耗内存:LinkedList比ArrayList消耗更多的内存,因为LinkedList中的每个节点都存储前后节点的引用。(双向链表)
ArrayList和Vector的区别?
- 线程安全性:ArrayList是非线程安全的,Vector是线程安全的,如果需要再迭代的时候对列表进行改变,使用CopyOnWriteArrayList。
- 效率:ArrayList是非同步的,效率高;Vector是同步的,效率低;
ArrayList和CopyOnWriteArrayList的区别
- 和ArrayList继承于AbstractList不同,CopyOnWriteArrayList没有继承于AbstractList,它仅仅只是实现了List接口。
- ArrayList的iterator()函数返回的Iterator是在AbstractList中实现的;而CopyOnWriteArrayList是自己实现Iterator。
- ArrayList的Iterator实现类中调用next()时,会“调用checkForComodification()比较’expectedModCount’和’modCount’的大小”;但是,CopyOnWriteArrayList的Iterator实现类中,没有所谓的checkForComodification(),更不会抛出ConcurrentModificationException异常!
Iterater和ListIterator区别
- 遍历目标:可以使用Iterator来遍历Set和List集合;而ListIterator只能遍历List。
- 遍历方向:Iterator只可以后向顺序遍历;而ListIterator可以双向遍历。
- 功能区别:ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。
Java—List集合详解相关推荐
- Java—Set集合详解(HashSet/LinkedHashSet/TreeSet/EnumSet)
关注微信公众号:CodingTechWork,一起学习进步. Set集合介绍 Set集合的概念 Set集合类似于一个容器,程序把很多对象保存到Set集合中,Set集合对添加顺序不记录,当有重复的对 ...
- java常用集合详解
文章目录 一.常用集合大纲 1.常用集合框架及介绍 2.集合和数组的区别 二.Collection 集合(接口) 三.List集合(接口) 1.存储遍历方式 2.ArrayList(实现类) 3.Li ...
- Java Set集合详解及Set与List的区别
Set是什么? Java中的Set集合是继承Collection的接口,是一个不包含重复元素的集合. 下图是Set集合的源码. Set和List都是以接口的形式来进行声明.Set主要包含三种存放数据类 ...
- Java—Map集合详解(HashMap/Hashtable/LinkedHashMap/Properties/TreeMap/WeakHashMap/IdentityHashMap/EnumMap)
关注微信公众号:CodingTechWork,一起学习进步. Map Map集合介绍 Map(也称为字典.关联数组)是用于保存具有映射关系的数据,保存两组值,key和value,这两组值可以是任何 ...
- java map集合详解_JAVA干货:Map 集合详解
java.util.Map集合 Map集合的特点: 1.Map集合是一个双列集合,一个元素包含两个值(一个key,一个value) 2.Map集合中的元素,key和value的数据类型可以相同,也可以 ...
- 【Java专题】Java泛型集合详解
一.什么是泛型? 1.先来看不是泛型的ArrayList集合 ArrayList集合的底层是一个object[]数组,但是它跟数组比起来又有很多的优势,它可以存很多不同类型的数据.问题出现在数据被取出 ...
- Java~Map集合详解
文章目录 Map介绍 核心Map 内部哈希:哈希映射技术 常用方法 遍历Map Map介绍 java.util中的集合类包含Java中某些最常用的类,其中最常用的集合类就是List和Map. 并且在集 ...
- Java Set集合详解
一:set集合框架体系图 二:set集合介绍 Set接口继承了Collection接口,含有许多常用的方法. int size();返回集合的长度 boolean isEmpty();判断集合是否为空 ...
- Java集合详解之Map
一.首先看看集合框架体系图 从图中可以看到,Map接口扩展了Iterator接口,关于Iterator接口详解请移步:Iterator接口详解 二.Map是什么? Map<k,v>使用键值 ...
最新文章
- Dictionary解析json,里面的数组放进list,并绑定到DataGridView指定列
- DW1000 TX POWER (发射功率) 解析
- Ibatis学习总结1--ibatis简介和SQL Maps
- Python中高级变量类型(列表,元组,字典,字符串,公共方法...)
- 打包指令_Linux系统常用指令总结
- mysql添加新用户
- mysql选取最小值_MySQL:选择x最小值
- Hadoop框架:集群模式下分布式环境搭建
- 实验5.2 动态内存分配生成动态数组完成矩阵转置
- 文件名lin.php是什么,宝塔面板-PHP服务添加‘扩展名=ixed.5.4.lin
- 1081. 不同字符的最小子序列
- 北大青鸟S1结业项目团队第一名——Myktv前端
- springboot jsonp 跨域请求,springboot使用jsonp跨域
- Java面向对象知识点总结
- 固克节能被终止创业板注册:年营收9.8亿 碧桂园创投是股东
- 合成大西瓜html5游戏,关于html5:魔改和上线你的合成大西瓜最全教程
- M365 比较 WLB?而 Bing 加班很猛?我也吃了一鲸!
- 常见软件环境的配置、下载...
- Nestjs中的守卫
- timestamp 6 mysql_Oracle timestamp(6)运用
热门文章
- STM32那点事(3)_中断(上)
- 01_Influxdb1.7.7的安装配置启动
- @excel 注解_Java中注解学习系列教程-3
- Swiper4.5在vue项目中的使用方法
- element-UI级联选择器(Cascader)获取label值 - 代码篇
- vue-router配置介绍和使用方法(二)
- 通信系统的monte carl仿真_深国电公司电力物联仿真检测系统建成投运
- YShout一款PHP+TXT+Ajax嵌入式在线聊天室源码
- CSS Scan扫描审核复制插件
- 机器人多用途综合官网展示PHP单页源码