目录
- 前言
- 一、常用List
- 1.1 List
- 1.1.1 特点
- 1.1.2 常用API
- 1.2 ArrayList
- 1.2.1 特点
- 1.2.2 使用
- 1.3 LinkedList
- 1.3.1 特点
- 1.3.2 使用
- 1.4 CopyOnWriteArrayList
- 1.4.1 特点
- 1.4.2 使用
- 1.5 Arrays.asList()
- 1.5.1 特点
- 1.5.2 使用
- 二、对比总结
前言
一、常用List
1.1 List
List是Java集合框架中的接口,表示有序的集合,可以包含重复元素。
public interface List<E> extends Collection<E> {
1.1.1 特点
特点:允许元素重复,有序集合,可以通过索引访问元素。
1.1.2 常用API
api | 作用描述 |
---|---|
boolean add(E element) | 将指定元素添加到列表的末尾。 |
void add(int index, E element) | 在指定位置插入元素。 |
E get(int index) | 返回指定位置的元素。 |
E remove(int index) | 移除指定位置的元素。 |
boolean remove(Object o) | 移除指定元素。 |
boolean contains(Object o) | 判断列表是否包含指定元素。 |
int size() | 返回列表中的元素个数。 |
boolean isEmpty() | 判断列表是否为空。 |
void clear() | 清空列表中的所有元素。 |
E set(int index, E element) | 将指定位置的元素替换为新元素。 |
1.2 ArrayList
ArrayList是基于数组实现的动态数组。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
1.2.1 特点
ArrayList的特点:支持随机访问元素,插入和删除元素效率较低。
1.2.2 使用
public static void test1() {
//使用ArrayList类创建列表
List<Integer> numbers = new ArrayList<>();
//将元素添加到列表
numbers.add(1);
numbers.add(2);
numbers.add(3);
System.out.println("List: " + numbers);
//从列表中访问元素
int number = numbers.get(2);
System.out.println("访问元素: " + number);
//从列表中删除元素
int removedNumber = numbers.remove(1);
System.out.println("删除元素: " + removedNumber);
}
输出:
1.3 LinkedList
LinkedList是基于双向链表实现的列表。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
1.3.1 特点
特点:适合插入和删除元素,但随机访问元素效率较低。
LinkedList与ArrayList的区别:
LinkedList和ArrayList都实现Collections框架的List接口。 但是,它们之间存在一些差异。
LinkedList | ArrayList |
---|---|
在单个位置存储3个值(上一个地址,数据和下一个地址) | 将单个值存储在单个位置 |
提供list的双链接列表实现 | 提供可调整大小的数组实现 |
每当添加元素时,上一个和下一个地址都会更改 | 每当添加元素时,该位置之后的所有元素都会移动 |
要访问元素,我们需要从头开始迭代到元素 | 可以使用索引随机访问元素。 |
1.3.2 使用
addFirst() - 将指定的元素添加到链接列表的开头
addLast() - 将指定的元素添加到链接列表的末尾
public static void test1() {
Deque<String> animals = new LinkedList<>();
//在LinkedList的开始处添加元素
animals.addFirst("Cow");
animals.addFirst("Dog");
animals.addFirst("Cat");
System.out.println("LinkedList: " + animals);
//在LinkedList的末尾添加元素
animals.addLast("Zebra");
System.out.println("新的LinkedList: " + animals);
}
输出:
1.4 CopyOnWriteArrayList
CopyOnWriteArrayList是线程安全的ArrayList,使用写时复制的机制。
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
1.4.1 特点
优点:适合多线程环境下遍历频繁、修改少的场景,支持并发读取,解决开发工作中的多线程并发问题
缺点:
- 内存占用问题:两个数组同时驻扎在内存中,如果实际应用中,数据比较多,而且比较大的情况下,占用内存会比较大,针对这个其实可以使用ConcurrentHashMap来代替。
- 数据一致性:CopyOnWriteArrayList容器只能保证数据的最终已执行,不能保证数据的实时一致性,所以如果希望写入的数据,马上能读取到,就不能使用CopyOnWriteArrayList。
CopyOnWriteArrayList详细内容查看如下文章:
CopyOnWriteArrayList详解及使用
1.4.2 使用
public class myCopyOnWriteArrayList {
public static void main(String[] args) {
startTest();
}
private static final Integer THREAD_POOL_MAX_SIZE = 10;
// 不支持并发
// private static List<String> mList = new ArrayList<>();
// 支持并发
private static List<String> mList = new CopyOnWriteArrayList<>();
private static void startTest() {
// 初始化数据
for (int i = 0; i < 10; i++) {
mList.add("line:" + (i + 1) + "data");
}
System.out.println("------------初始化完成--------------------------");
ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_MAX_SIZE);
// 读写并发测试
for (int i = 0; i < THREAD_POOL_MAX_SIZE; i++) {
// 读任务立即执行
executorService.execute(() -> {
for (String item : mList) {
System.out.println(Thread.currentThread().getName() + "数据:" + item);
}
});
final int final1 = i + 10;
// 写任务立即执行
executorService.execute(() -> {
mList.add("写线程添加数据" + final1 + "..............");
});
}
}
}
1.5 Arrays.asList()
Arrays.asList():将数组转换为List的静态方法。
List< String> list = Arrays.asList(“a”,“b”,“c”);
注意:
(1)该方法适用于对象型数据的数组(String、Integer…)
(2)该方法不建议使用于基本数据类型的数组(byte,short,int,long,float,double,boolean)
(3)该方法将数组与List列表链接起来:当更新其一个时,另一个自动更新
(4)不支持add()、remove()、clear()等方法
(5)用此方法得到的List的长度是不可改变的
1.5.1 特点
特点:方便将数组转换为List,但返回的List不支持增删操作
。
1.5.2 使用
public static void test1(){
//1、使用asList()的String数组,正常
String[] strings = {"aa", "bb", "cc"};
List<String> stringList = Arrays.asList(strings);
System.out.print("1、使用asList()的String数组,正常: ");
for(String str : stringList){
System.out.print(str + " ");
}
System.out.println();
//2、使用asList()的对象类型(Integer)数组,正常
Integer[] integers = new Integer[] {1, 2, 3};
List<Integer> integerList = Arrays.asList(integers);
System.out.print("2、使用asList()的对象类型数组,正常: ");
for(int i : integerList){
System.out.print(i + " ");
}
System.out.println();
//3、使用asList()的基本数据类型数组,出错
int[] ints = new int[]{1, 2, 3};
List intList = Arrays.asList(ints);
System.out.print("3、使用asList()的基本数据类型数组,出错(将'ints'视为单个元素):");
for(Object o : intList){
System.out.print(o.toString());
}
System.out.println();
System.out.print(" " + "要正确输出,需按如下方式遍历:");
int[] ints1 = (int[]) intList.get(0);
for(int i : ints1){
System.out.print(i + " ");
}
System.out.println();
//4、更新数组或List时,另一个将自动更新
System.out.print("4、更新数组或List时,另一个将自动更新: ");
integerList.set(0, 5);
for(Object o : integerList){
System.out.print(o + " ");
}
for(Object o : integers){
System.out.print (o + " ");
}
System.out.println();
//5、add() remove() 将报错
System.out.print("5、add() remove() 将报错: ");
// integerList.remove(0);
// integerList.add(3, 4);
// integerList.clear();
}
输出:
二、对比总结
list | 特点 | 适用场景 |
---|---|---|
ArrayList | 基于数组实现,支持动态扩容,随机访问元素效率高。 | 需要频繁随机访问元素,对插入和删除操作要求不是特别高的场景。 |
LinkedList | 基于双向链表实现,插入和删除元素效率高,但随机访问元素效率相对较低。 | 需要频繁插入和删除元素,而对随机访问元素要求不高的场景。 |
CopyOnWriteArrayList | 线程安全,使用写时复制的机制实现。 | 多线程环境下需要频繁遍历而很少修改List的场景。 |
Arrays.asList() | 将数组转换为List。 | 需要将数组转换为List的场景。 |
参考链接:
Java LinkedList(链表)
CopyOnWriteArrayList详解及使用
Arrays.asList() 详解