一.LinkedList简介
LinkedList是实现List接口的。因为它是基于双向链表实现的,主要有如下特点:
1、插入、删除比较快,因为插入、删除只需要改变连接,新的节点可以在内存中的任何地方。
2、可以重复插入数据、可以插入null。
3、查找比较慢,不能随即访问,虽然存在get()方法,但是这个方法是通过遍历接点来定位的,所以速度慢。
LinkedList的底层实现是不同步,多线程操作会出现问题,这一点要注意。
二.LinkedList常用方法
1.add(E e):向集合中添加一个元素
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
2.add(int index, E element):向集合index位置处添加一个元素
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add(0, "张三");
3.addAll(Collection<? extends E> c):将某集合全部添加到另外一集合
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("刘六");
linkedList.add("王二麻子");
LinkedList<String> allLinkedList = new LinkedList<String>();
allLinkedList.addAll(linkedList);
4.addAll(int index, Collection<? extends E> c):将某集合全部添加到另外一集合的index位置处
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("刘六");
linkedList.add("王二麻子");
LinkedList<String> allLinkedList = new LinkedList<String>();
allLinkedList.addAll(2, linkedList);
5.set(int index, E element):修改index位置对应的Object
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.set(0, "李四");;
6.remove(int index):移除此列表中指定位置上的元素。
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.remove(0);
7. remove(Object o):如果存在移除此列表中首次出现的指定元素。
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.remove("张三");
8.remove():删除第一个元素。
public class CollectionActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection);
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("刘六");
linkedList.add("王二麻子");
String result = linkedList.remove();
Log.d("TAG", "result----:" + result);
Iterator<String> iterator = linkedList.iterator();
while (iterator.hasNext()) {
Log.d("TAG", iterator.next() + "");
}
}
}
D/TAG: result----:张三
D/TAG: 李四
D/TAG: 王五
D/TAG: 刘六
D/TAG: 王二麻子
9.get(int index)方法:获取index位置对应的Object
LinkedList<String> linkedList = new LinkedList<String>();
String s = linkedList.get(0);
10.subList(int fromIndex,int toIndex)方法:截取集合[fromIndex,toIndex)
public class CollectionActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection);
initArrayList();
}
public void initArrayList() {
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("小利");
List<String> newList = linkedList.subList(1, linkedList.size());
Iterator<String> iterator = newList.iterator();
while (iterator.hasNext()) {
Log.i("TAG", iterator.next() + "");
}
}
}
I/TAG: 李四
I/TAG: 王五
I/TAG: 小利
注:toIndex 要考虑数组下标越界问题。
List<String> newlist = linkedList.subList(1, linkedList.size()+10);
报错。
11.size()方法:集合长度
LinkedList<String> linkedList = new LinkedList<String>();
int num = linkedList.size();
12.isEmpty():集合是否为空
LinkedList<String> linkedList = new LinkedList<String>();
boolean b = linkedList.isEmpty();
13.contains(Object o):集合是否包含o
LinkedList<String> linkedList = new LinkedList<String>();
boolean b = linkedList.contains("张三");
14.indexOf(Object o):集合中第一次出现o的位置
public class CollectionActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection);
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("张三");
linkedList.add("刘六");
linkedList.add("王二麻子");
linkedList.add("张三");
int a = linkedList.indexOf("张三");
int b = linkedList.indexOf("刘六");
int c = linkedList.indexOf("222");
Log.d("TAG", "a----:" + a);
Log.d("TAG", "b----:" + b);
Log.d("TAG", "c----:" + c);
}
}
D/TAG: a----:0
D/TAG: b----:4
D/TAG: c----:-1
15.lastIndexOf(Object o):集合中最后一次出现o的位置
public class CollectionActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection);
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("张三");
linkedList.add("刘六");
linkedList.add("王二麻子");
linkedList.add("张三");
int d = linkedList.lastIndexOf("张三");
int e = linkedList.lastIndexOf("刘六");
int f = linkedList.lastIndexOf("222");
Log.d("TAG", "d----:" + d);
Log.d("TAG", "e----:" + e);
Log.d("TAG", "f----:" + f);
}
}
D/TAG: d----:6
D/TAG: e----:4
D/TAG: f----:-1
16.clear():清空集合中的所有元素
public class CollectionActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection);
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("张三");
linkedList.add("刘六");
linkedList.add("王二麻子");
linkedList.add("张三");
linkedList.clear();
Log.d("TAG", "*********************遍历集合***************************");
Iterator<String> iterator = linkedList.iterator();
while (iterator.hasNext()) {
Log.d("TAG", iterator.next() + "");
}
}
}
D/TAG: *********************遍历集合***************************
17.addFirst(E e):向集合头部添加元素
public class CollectionActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection);
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.addFirst("First");
Log.d("TAG", "*********************遍历集合***************************");
Iterator<String> iterator = linkedList.iterator();
while (iterator.hasNext()) {
Log.d("TAG", iterator.next() + "");
}
}
}
D/TAG: *********************遍历集合***************************
D/TAG: First
D/TAG: 张三
D/TAG: 李四
D/TAG: 王五
18.addLast(E e):向集合尾部添加元素
public class CollectionActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection);
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.addLast("Last");
Log.d("TAG", "*********************遍历集合***************************");
Iterator<String> iterator = linkedList.iterator();
while (iterator.hasNext()) {
Log.d("TAG", iterator.next() + "");
}
}
}
D/TAG: *********************遍历集合***************************
D/TAG: 张三
D/TAG: 李四
D/TAG: 王五
D/TAG: Last
19.getFirst():返回集合的第一个元素
public class CollectionActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection);
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
String s = linkedList.getFirst();
Log.d("TAG", "s----:" + s);
}
}
D/TAG: s----:张三
20.getLast():返回集合最后一个元素
public class CollectionActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collection);
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
String s = linkedList.getLast();
Log.d("TAG", "s----:" + s);
}
}
D/TAG: s----:王五
三.LinkedList源码分析
我们从LinkedList的构造方法开始我们的源码之旅。
源码分析之构造方法
1.无参构造方法
使用
LinkedList<String> linkedList = new LinkedList<String>();
源码
/**
* Constructs an empty list.
*/
public LinkedList() {
}
2.有参构造方法(传参Collection类型)
使用
ArrayList arrayList = new ArrayList();
arrayList.add("张三");
LinkedList<String> linkedList = new LinkedList<String>(arrayList);
源码
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
源码分析之直接添加元素
举例
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
源码
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #addLast}.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
linkLast(e);
return true;
}
linkLast()方法源码
/**
* Links e as last element.
*/
void linkLast(E e) {
//将全局变量last 赋值给l变量 last就是链表中的上一个元素
final Node<E> l = last;
//使用上一个元素和传参的当前元素创建一个新的元素
final Node<E> newNode = new Node<>(l, e, null);
//将刚刚生成的新的元素赋值给last
last = newNode;
if (l == null)//如果l变量为空 即链表中的上一个元素为空 也就是链表为空
first = newNode;//新元素放到第一个
else//否则 也就是链表中上一个元素不为空 也就是链表不为空
l.next = newNode;//新元素放到上一个元素的下一个
size++;
modCount++;
}
该方法涉及到的全局变量
//全局变量 第一个元素
transient Node<E> first;
//全局变量 上一个元素
transient Node<E> last;
//全局变量 链表长度 元素个数
transient int size = 0;
//全局变量 链表长度 The number of times this list has been structurally modified
protected transient int modCount = 0;
该方法涉及到的类Node 内部静态类
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
由源码可知
添加元素时,先使用上一个元素和当前传参的元素生产新的Node。
如果上一个元素为空 则将新生成的元素赋值给Node<E> first。即将新生成的元素当成链表中的头元素。
如果上一个元素不为空 则将新生成的元素赋值给l.next。即将新生成的元素放到上一个元素的下一个元素。
源码分析之向指定位置添加元素方法
举例
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add(2, "张三");
源码
/**
* Inserts the specified element at the specified position in this list.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
首先,执行第一行代码checkPositionIndex()方法。
checkPositionIndex()方法源码
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
isPositionIndex()方法源码
/**
* Tells if the argument is the index of a valid position for an
* iterator or an add operation.
*/
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
也就是说,checkPositionIndex()方法就是校验传入的index是否合法。不合法抛出异常。
if (index == size){
linkLast(element);
}
如果,传参的inex等于size。也就是说传入元素的位置是最后一个。那么执行linkLast(element);方法。此方法源码上述已分析,不再赘述。即 相当于添加一个新的元素。
else{
linkBefore(element, node(index));
}
如果,传参的index不等于size。需要执行linkBefore(element, node(index));方法。传参node(index)
node(index)方法源码
/**
* Returns the (non-null) Node at the specified element index.
*/
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
size>>1:即将size右移两位 10>>1==5。 4>>1==2 3>>1==1 右移两位相当于除以2后的整数。
如果,传参index小于(size>>1)。也就是index小于size/2的整数值 则在链表的前半部分查找。返回新的Node对象。
如果,传参index大于等于(size>>1)。也就是index大于等于size/2的整数值 则在链表的后半部分查找。返回新的Node对象。
然后使用新生成的Node对象。当成参数执行linkBefore(element, node(index));方法。
linkBefore(element, node(index));方法源码
/**
* Inserts element e before non-null Node succ.
*/
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
将传参的元素的上一个元素赋值给Node<E> pred。然后使用Node<E> pred和传参要插入的元素和刚刚生成的新元素。再生成一个新的元素。 Node<E> newNode。并且将新的元素赋值给刚刚生成元素的上一个元素。
如果,上一个元素为空 则新元素放到链表中第一个元素。
如果,上一个元素不为空 则新元素放到刚刚生成的元素的下一个元素。
小结1
由源码可知,LinkedList中添加元素时,只需要新生成一个Node。然后操作Node的next(下一个元素)和prev(上一个元素)即可。不需要向ArrayList一样。移动数组中的数据。
源码分析之获取指定位置元素方法
使用
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.get(0);
源码
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
checkElementIndex(index);方法。上述已经讲过。就是校验传参位置index。是否合法。
由源码可知,LinkedList的get方法 再get时。需要用传参的位置index。先生成一个Node对象。
/**
* Returns the (non-null) Node at the specified element index.
*/
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
小结2
源码也可得知,LinkedList。获取指定位置上的元素时,需要先生成一个Node对象。而生成Node对象时,还要判断获取的位置在上半部分还是在下半部分。其实相当于遍历整个链表。所以比较耗时。
源码分析之获取删除指定位置元素方法
使用
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.remove(1);
源码
/**
* Removes the element at the specified position in this list. Shifts any
* subsequent elements to the left (subtracts one from their indices).
* Returns the element that was removed from the list.
*
* @param index the index of the element to be removed
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
首先,校验传参的位置index是否合法。然后执行unlink(node(index));方法。传参node(index)。这个方法上述已经讲过,在此不再赘述。
unlink()方法源码
/**
* Unlinks non-null node x.
*/
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
大致的意思,就是操作Node对象的next和prev。
小结3
由源码可知,删除元素时,LinkedList只需生成一个Node对象。然后操作Node的next(下一个元素)和prev(上一个元素)即可。不需要向ArrayList一样。移动数组中的数据。
四.LinkedList删除数据事项
1.remove(int inedex)删除
代码
package com.example.test;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Iterator;
import java.util.LinkedList;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initArrayList();
}
public void initArrayList() {
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("刘六");
linkedList.add("王二麻子");
/**
* 删除“王五”后立刻取出“刘六”
* */
//方法1.remove(int index)
linkedList.remove(2);
String result = linkedList.get(3);
Log.i("TAG", "3位置上对应的结果----:" + result);
Log.i("TAG", "删除“王五”后立刻取出“刘六”遍历集合");
Iterator<String> iterator = linkedList.iterator();
while (iterator.hasNext()) {
Log.i("TAG", iterator.next() + "");
}
}
}
结果
I/TAG: 3位置上对应的结果----:王二麻子
I/TAG: 删除“王五”后立刻取出“刘六”遍历集合
I/TAG: 张三
I/TAG: 李四
I/TAG: 刘六
I/TAG: 王二麻子
2.remove(Object o)方法
代码
package com.example.test;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Iterator;
import java.util.LinkedList;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initArrayList();
}
public void initArrayList() {
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("刘六");
linkedList.add("王二麻子");
/**
* 删除“王五”后立刻取出“刘六”
* */
//方法2.remove(Object o)
linkedList.remove("王五");
String result = linkedList.get(3);
Log.i("TAG", "3位置上对应的结果----:" + result);
Log.i("TAG", "删除“王五”后立刻取出“刘六”遍历集合");
Iterator<String> iterator = linkedList.iterator();
while (iterator.hasNext()) {
Log.i("TAG", iterator.next() + "");
}
}
}
结果
I/TAG: 3位置上对应的结果----:王二麻子
I/TAG: 删除“王五”后立刻取出“刘六”遍历集合
I/TAG: 张三
I/TAG: 李四
I/TAG: 刘六
I/TAG: 王二麻子
3.Iterator.remove()方法删除
代码
package com.example.test;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Iterator;
import java.util.LinkedList;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initArrayList();
}
public void initArrayList() {
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("刘六");
linkedList.add("王二麻子");
/**
* 删除“王五”后立刻取出“刘六”
* */
//方法3.Iterator.remove()
Iterator iter = linkedList.iterator();
while (iter.hasNext()) {
if (iter.next().equals("王五")) {
iter.remove();
}
}
String result = linkedList.get(3);
Log.i("TAG", "3位置上对应的结果----:" + result);
Log.i("TAG", "删除“王五”后立刻取出“刘六”遍历集合");
Iterator<String> iterator = linkedList.iterator();
while (iterator.hasNext()) {
Log.i("TAG", iterator.next() + "");
}
}
}
结果
I/TAG: 3位置上对应的结果----:王二麻子
I/TAG: 删除“王五”后立刻取出“刘六”遍历集合
I/TAG: 张三
I/TAG: 李四
I/TAG: 刘六
I/TAG: 王二麻子
说明
集合的删除 一般情况下使用remove(int inedex),remove(Object o)或是Iterator.remove()方法都可以。(比如上述删除某个已知的元素(要删除的元素位置和值都确定且只删除一个))。
而要遍历集合删除循环删除时建议使用迭代器的删除即Iterator.remove()方法删除。
举例
代码
package com.example.test;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Iterator;
import java.util.LinkedList;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initArrayList();
}
public void initArrayList() {
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("刘六");
linkedList.add("王二麻子");
int num = linkedList.size();
for (int i = 0; i < num; i++) {
String s = linkedList.get(i);
if ("李四".equals(s)) {
linkedList.remove("李四");
}
}
Log.i("TAG", "*********************遍历集合***************************");
Iterator<String> iterator = linkedList.iterator();
while (iterator.hasNext()) {
Log.i("TAG", iterator.next() + "");
}
}
}
结果
报错(数组下标越界)
代码
package com.example.test;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Iterator;
import java.util.LinkedList;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initArrayList();
}
public void initArrayList() {
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("张三");
linkedList.add("李四");
linkedList.add("王五");
linkedList.add("刘六");
linkedList.add("王二麻子");
Iterator iter = linkedList.iterator();
while (iter.hasNext()) {
if (iter.next().equals("李四")) {
iter.remove();
}
}
Log.i("TAG", "*********************遍历集合***************************");
Iterator<String> iterator = linkedList.iterator();
while (iterator.hasNext()) {
Log.i("TAG", iterator.next() + "");
}
}
}
结果
I/TAG: *********************遍历集合***************************
I/TAG: 张三
I/TAG: 王五
I/TAG: 刘六
I/TAG: 王二麻子
正确
五.总结
因为它是基于双向链表实现的,主要有如下特点:
1.插入、删除比较快,每一个节点都包含前一个节点的引用,后一个节点的引用和节点存储的值。当一个新节点插入时,只需要修改其中保持先后关系的节点的引用即可,当删除记录时也一样。
2.可以重复插入数据、可以插入null。
3. 查找比较慢,虽然存在get()方法,但是这个方法是通过遍历接点来定位的,所以速度慢。
所以。
如果使用集合时,更多的是通过下标找指定元素。那么建议使用ArrayList。
如果使用集合时,需要频繁的删除或者插入元素。那么建议使用LinkedList。
ArrayList详解:https://blog.csdn.net/weixin_37730482/article/details/73614116