文章目录
List接口详解
List接口的定义
List接口是Java集合框架中的一个接口,继承自Collection接口。List接口用于表示一个有序、可重复的集合,可以通过索引(位置)来访问和修改其中的元素。List接口的常用实现类包括ArrayList、LinkedList和Vector等。
List接口定义的方法
- 添加元素:add(E e)、add(int index, E element)、addAll(Collection<? extends E> c)、addAll(int index, Collection<? extends E> c)等方法;
- 删除元素:remove(Object o)、remove(int index)、removeAll(Collection<?> c)等方法;
- 获取元素:get(int index)、subList(int fromIndex, int toIndex)等方法;
- 修改元素:set(int index, E element)等方法;
- 获取列表大小:size()方法;
- 判断列表是否为空:isEmpty()方法;
- 判断是否包含某个元素:contains(Object o)、containsAll(Collection<?> c)等方法;
- 清空列表:clear()方法;
- 获取列表中某个元素的索引位置:indexOf(Object o)、lastIndexOf(Object o)等方法;
- 迭代器:listIterator()、listIterator(int index)等方法。
List接口还定义了一些特殊的操作,比如获取子列表、反转列表等,以及用于排序的sort方法。
List接口的常用子类
ArrayList
实现了可调整大小的数组,支持快速随机访问,插入和删除操作的效率较低;
LinkedList
实现了基于双向链表的列表,支持快速插入和删除操作,但不支持随机访问;
Vector
类似于ArrayList,但是是线程安全的,因此效率较低,已经不建议使用,可以使用CopyOnWriteArrayList代替;
CopyOnWriteArrayList
是一个线程安全的ArrayList,每次修改时都会复制一份新的数组,因此不适合大量的修改操作。
LinkedList 子类与 Queue 接口
LinkedList是Java中List接口的一个实现类,同时也实现了Deque和Queue接口。Queue是Java中一个单独的接口,继承自Collection接口,代表了一组队列操作,比如添加元素到队列尾部、从队列头部取出元素等。
LinkedList作为一个List集合实现,可以进行List中的各种操作,同时作为一个Queue实现,也可以进行队列操作。可以使用LinkedList实现先进先出(FIFO)的队列,也可以实现后进先出(LIFO)的栈。
深入探讨ArrayList和LinkedList的使用场景和优劣
ArrayList和LinkedList是Java中常用的List集合实现类,它们都实现了List接口,但是底层实现机制不同,因此在不同的场景下,选择使用哪个集合会有不同的效果。
ArrayList是基于数组实现的动态数组,它的优点是支持快速随机访问,因为元素在内存中是连续存储的,因此可以通过索引直接访问到元素。同时,由于ArrayList底层采用的是数组实现,因此可以提供高效的随机访问、添加、删除等操作。缺点是在进行添加或删除操作时需要进行大量的数组复制操作,如果数据量比较大的话,这些操作会非常耗时。另外,由于ArrayList内部使用数组实现,因此它的大小是固定的,当元素数量超出数组大小时,需要进行扩容操作,也会导致性能问题。
LinkedList是基于链表实现的列表,它的优点是支持快速的插入和删除操作,因为只需要改变节点的指向即可,不需要进行数组复制操作。另外,LinkedList在进行插入和删除操作时不需要移动其他元素的位置,因此它的效率不受集合大小的影响。缺点是访问元素时需要遍历链表,因此效率较低,不支持随机访问。
从上述特点来看,当需要进行随机访问时,使用ArrayList会更加高效,因为它可以直接通过索引访问元素。而当需要进行插入和删除操作时,使用LinkedList会更加高效,因为它不需要进行数组复制操作。
另外,需要注意的是,在多线程环境下,ArrayList和LinkedList都不是线程安全的,因此需要进行同步处理。如果需要在多线程环境下使用List集合,可以使用线程安全的CopyOnWriteArrayList,或者使用Collections.synchronizedList方法包装List集合实现同步操作。
总之,对于需要进行随机访问操作的场景,选择ArrayList会更加高效,而对于需要进行插入和删除操作的场景,选择LinkedList会更加高效。同时,需要考虑集合的大小和多线程安全等因素,在选择使用哪个集合时,需要进行综合考虑。
示例代码
示例1:向集合中增加元素、删除元素、输出全部元素、将集合变为对象数组的操作
import java.util.ArrayList;
import java.util.List;
public class CollectionDemo {
public static void main(String[] args) {
// 创建一个 List 集合
List<String> list = new ArrayList<>();
// 向集合中添加元素的方法1:add()
list.add("apple");
list.add("banana");
list.add("cherry");
// 向集合中添加元素的方法2:addAll()
List<String> moreFruits = new ArrayList<>();
moreFruits.add("durian");
moreFruits.add("elderberry");
moreFruits.add("fig");
list.addAll(moreFruits);
// 输出集合中所有元素
System.out.println("输出集合中所有元素:");
for (String fruit : list) {
System.out.println(fruit);
}
// 将集合变为对象数组的方法1:toArray()
Object[] objArr = list.toArray();
System.out.println("\n将集合变为对象数组的方法1:");
for (int i = 0; i < objArr.length; i++) {
System.out.print(objArr[i] + " ");
}
// 将集合变为对象数组的方法2:toArray(T[] a)
String[] strArr = list.toArray(new String[0]); // 注意:传入的参数类型要与目标数组元素类型一致
System.out.println("\n\n将集合变为对象数组的方法2:");
for (int i = 0; i < strArr.length; i++) {
System.out.print(strArr[i] + " ");
}
// 从集合中删除元素的方法1:remove()
list.remove("banana");
// 从集合中删除元素的方法2:removeAll()
List<String> toRemove = new ArrayList<>();
toRemove.add("cherry");
toRemove.add("fig");
list.removeAll(toRemove);
// 输出删除元素后集合中所有元素
System.out.println("\n\n删除元素后集合中所有元素:");
for (String fruit : list) {
System.out.println(fruit);
}
}
}
示例2:对List进行截取、查找元素位置、判断元素是否存在、集合是否为空等操作
import java.util.ArrayList;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
// 创建一个List集合,并添加一些元素
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
list.add("JavaScript");
list.add("PHP");
System.out.println("集合中的元素为:" + list);
// 截取集合中的元素
List<String> subList = list.subList(1, 4);
System.out.println("截取后的集合中的元素为:" + subList);
// 查找元素位置
int index1 = list.indexOf("C++");
int index2 = list.indexOf("Ruby");
System.out.println("元素C++的位置为:" + index1);
System.out.println("元素Ruby的位置为:" + index2);
// 判断元素是否存在
boolean contains1 = list.contains("Python");
boolean contains2 = list.contains("Perl");
System.out.println("集合中是否包含元素Python:" + contains1);
System.out.println("集合中是否包含元素Perl:" + contains2);
// 判断集合是否为空
boolean isEmpty1 = list.isEmpty();
list.clear();
boolean isEmpty2 = list.isEmpty();
System.out.println("集合是否为空:" + isEmpty1);
System.out.println("清空集合后,集合是否为空:" + isEmpty2);
}
}
示例3:LinkedList的一些常用方法
import java.util.LinkedList;
import java.util.Queue;
public class LinkedListQueueExample {
public static void main(String[] args) {
// 创建一个 LinkedList 实例
LinkedList<String> linkedList = new LinkedList<>();
// 将元素添加到队列尾部
linkedList.add("A");
linkedList.add("B");
linkedList.add("C");
// 使用队列方法取出队列头部元素并删除该元素
System.out.println(linkedList.poll()); // 输出 A
// 使用队列方法取出队列头部元素但不删除该元素
System.out.println(linkedList.peek()); // 输出 B
// 使用队列方法获取队列大小
System.out.println(linkedList.size()); // 输出 2
// 将元素添加到队列尾部
linkedList.offer("D");
// 遍历队列并输出每个元素
for (String s : linkedList) {
System.out.println(s);
}
}
}
LinkedList实现了Queue接口中的
offer()
,poll()
和peek()
方法,用于在队列中添加元素、取出队列头部元素并删除该元素,以及取出队列头部元素但不删除该元素。此外,LinkedList还实现了List接口中的add()
方法,用于在队列尾部添加元素。同时,我们还可以使用size()
方法获取队列大小,在这个例子中输出了2,因为我们已经取出了队列中的第一个元素。
示例4:增加数据、找到链表头以及以FIFO方式取出内容
import java.util.LinkedList;
public class LinkedListDemo {
public static void main(String[] args) {
// 创建一个 LinkedList
LinkedList<String> linkedList = new LinkedList<>();
// 添加元素
linkedList.add("Java");
linkedList.add("Python");
linkedList.add("C++");
linkedList.add("JavaScript");
// 找到链表头
String head = linkedList.getFirst();
System.out.println("链表头为:" + head);
// 以FIFO方式取出内容
while (!linkedList.isEmpty()) {
String element = linkedList.poll(); // 弹出链表头元素
System.out.println("取出元素:" + element);
}
}
}