允许重复元素,有序。常见的实现类有 ArrayList
、LinkedList
、Vector
。
ArrayList
ArrayList
是在 Java 编程中常用的集合类之一,它提供了便捷的数组操作,并在动态性、灵活性和性能方面取得了平衡。如果需要频繁在中间插入和删除元素,或者需要在多线程环境中使用,可能需要考虑其他集合实现。
特点
1.动态大小: ArrayList
的大小是动态可变的,可以根据需要自动增加或缩小。这与 Vector
相似,但相对于 LinkedList
,它的随机访问效率更高。
2.随机访问高效: 由于 ArrayList
基于动态数组实现,可以通过索引直接访问元素,因此在需要频繁随机访问元素的场景下,ArrayList
的性能通常优于 LinkedList
。
3.适用于大部分场景: 在大多数情况下,ArrayList
是一个通用、高效的集合类。它适用于存储和随机访问元素,但不适用于在中间或开头频繁插入和删除元素的情况。
4.非同步: ArrayList
不是线程安全的,不支持多线程并发操作。如果需要在多线程环境中使用,可以考虑使用 Vector(这个比较落后了,所以就不提了)
或使用 Collections.synchronizedList
方法包装 ArrayList
。
使用方法
首先先引用,然后初始化。
import java.util.ArrayList;//引入ArrayList类
public class Test01 {
ArrayList<String> objectName = new ArrayList<>();//初始化
}
objectName:对象名。
ArrayList<String>:这<>里面的是泛型数据类型,用于设置 objectName 的数据类型,只能为引用数据类型。
一点示范
import java.util.ArrayList;//引入ArrayList类
public class Test01 {
public static void main(String[] args) {
ArrayList<String> objectName = new ArrayList<>();//初始化
objectName.add("Changsha");//add()
System.out.println(objectName);
objectName.add("Shenyang");
System.out.println(objectName);
objectName.set(0,"Shanghai");//set()
System.out.println(objectName);
System.out.println(objectName.get(1));//get()
objectName.remove(1);//remove()
System.out.println(objectName);
}
}
运行结果
用法表格
1 | add() | 将元素插入到指定位置的 arraylist 中 |
2 | addAll() | 添加集合中的所有元素到 arraylist 中 |
3 | clear() | 删除 arraylist 中的所有元素 |
4 | clone() | 复制一份 arraylist |
5 | contains() | 判断元素是否在 arraylist |
6 | get() | 通过索引值获取 arraylist 中的元素 |
7 | indexOf() | 返回 arraylist 中元素的索引值 |
8 | removeAll() | 删除存在于指定集合中的 arraylist 里的所有元素 |
9 | remove() | 删除 arraylist 里的单个元素 |
10 | size() | 返回 arraylist 里元素数量 |
11 | isEmpty() | 判断 arraylist 是否为空 |
12 | subList() | 截取部分 arraylist 的元素 |
13 | set() | 替换 arraylist 中指定索引的元素 |
14 | sort() | 对 arraylist 元素进行排序 |
15 | toArray() | 将 arraylist 转换为数组 |
16 | toString() | 将 arraylist 转换为字符串 |
17 | ensureCapacity() | 设置指定容量大小的 arraylist |
18 | lastIndexOf() | 返回指定元素在 arraylist 中最后一次出现的位置 |
19 | retainAll() | 保留 arraylist 中在指定集合中也存在的那些元素 |
20 | containsAll() | 查看 arraylist 是否包含指定集合中的所有元素 |
21 | trimToSize() | 将 arraylist 中的容量调整为数组中的元素个数 |
22 | removeRange() | 删除 arraylist 中指定索引之间存在的元素 |
23 | replaceAll() | 将给定的操作内容替换掉数组中每一个元素 |
24 | removeIf() | 删除所有满足特定条件的 arraylist 元素 |
25 | forEach() | 遍历 arraylist 中每一个元素并执行特定操作 |
LinkedList
特点
1.双向链表结构:这是它与ArrayList最主要的差别, LinkedList
的底层数据结构是双向链表,每个节点都包含对前一个和后一个元素的引用。
2.动态大小: 类似于 ArrayList
,LinkedList
的大小也是动态可变的,可以根据需要自动增加或缩小。
3.插入和删除效率高: 由于链表结构,LinkedList
在中间插入和删除元素的操作比 ArrayList
效率更高。因此在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。
4.非随机访问效率相对较低: 与 ArrayList
不同,LinkedList
的随机访问效率相对较低。如果需要频繁随机访问元素,ArrayList
可能更适合。
5.迭代效率: 在迭代时,LinkedList
的性能较差。由于访问节点需要跳跃指针,相比于数组的连续存储,会增加迭代的开销。
6.占用更多内存: 由于每个节点都需要存储额外的引用,相对于 ArrayList
,LinkedList
在内存占用上可能会更多。
7.非同步: LinkedList
也不是线程安全的,不支持多线程并发操作。如果需要在多线程环境中使用,可以考虑使用 Collections.synchronizedList
方法包装 LinkedList
。
8.特定场景的优势: 在某些特定的场景中,如实现栈、队列或双端队列等数据结构时,LinkedList
可能更为适用。
使用方法
同样是引用和初始化
import java.util.LinkedList;
public class Test01 {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
}
}
linkedList:对象名
LinkedList<String>:这<>里面的是泛型数据类型,用于设置 linkedList的数据类型,只能为引用数据类型。
一些示范
import java.util.LinkedList;
public class Test01 {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("Apple");
linkedList.add("Banana");
linkedList.add("Orange");
System.out.println(linkedList);
// 在指定位置插入元素
linkedList.add(1, "Grapes");
System.out.println(linkedList);
//获取链表中的元素:
String element = linkedList.get(0);
System.out.println(element);
//更新链表中的元素
linkedList.set(0, "NewElement");
System.out.println(linkedList);
}
}
运行结果
常见用法
1 | linkedList.add("Element"); | 在链表末尾添加元素 |
2 | linkedList.add(index, "Element"); | 在指定位置插入元素 |
3 | linkedList.get(index); | 获取链表中的元素 |
4 | linkedList.set(index, "NewElement"); | 更新链表中的元素 |
5 | linkedList.remove(index); | 删除指定位置的元素 |
6 | int size = linkedList.size(); | 获取链表的大小 |
7 | linkedList.isEmpty(); | 判断链表是否为空 |
8 | linkedList.contains("Element"); | 查找元素是否存在 |
9 | linkedList.getFirst();linkedList.getLast(); | 获取第一个和最后一个元素 |
10 | linkedList.removeFirst(); linkedList.removeLast(); | 删除第一个和最后一个元素 |
11 | Iterator<String> iterator = linkedList.iterator(); while (iterator.hasNext()) { String element = iterator.next(); // 处理元素 } | 迭代器遍历链表 |
12 | ListIterator<String> iterator = linkedList.listIterator(linkedList.size()); while (iterator.hasPrevious()) { String element = iterator.previous(); // 处理元素 } | 反向遍历链表 |
ArrayList 和 LinkedList 的性能对比
- ArrayList:适合频繁的随机访问操作,时间复杂度为O(1)。但在中间插入或删除元素时,时间复杂度为O(n),因为需要移动后续元素。
- LinkedList:适合频繁的插入和删除操作,时间复杂度为O(1)。但随机访问元素时,时间复杂度为O(n),因为需要从头或尾遍历链表。
- 对时间和空间不了解的可以看时间复杂度与空间复杂度详解(曼波版)-CSDN博客
线程安全
- ArrayList和LinkedList都不是线程安全的。如果需要在多线程环境中使用,可以使用Collections.synchronizedList来包装它们:
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
- 或者使用CopyOnWriteArrayList,它是线程安全的List实现,适合读多写少的场景。
迭代器
- ArrayList和LinkedList都支持Iterator和ListIterator。ListIterator提供了双向遍历的能力,可以在遍历过程中修改列表。
ListIterator<String> iterator = list.listIterator(); while (iterator.hasNext()) { String element = iterator.next(); // 处理元素 }
容量管理
- ArrayList在内部使用数组存储元素,当数组容量不足时会自动扩容。可以通过ensureCapacity(int minCapacity)方法来预先分配足够的容量,避免频繁扩容带来的性能开销。
ArrayList<String> list = new ArrayList<>(); list.ensureCapacity(100); // 预先分配100个元素的容量
LinkedList 的特殊方法
- LinkedList实现了Deque接口,因此可以用作栈或队列。它提供了addFirst、addLast、removeFirst、removeLast等方法,可以方便地实现栈和队列的操作。
LinkedList<String> queue = new LinkedList<>(); queue.addLast("A"); // 入队 String first = queue.removeFirst(); // 出队
性能优化建议
- 如果需要频繁在列表中间插入或删除元素,优先选择LinkedList。
- 如果需要频繁随机访问元素,优先选择ArrayList。
- 如果列表大小固定且已知,可以使用Arrays.asList来创建不可变的列表,减少内存开销。
List<String> fixedList = Arrays.asList("A", "B", "C");
进一步优化与迭代方向
- 性能测试:在实际项目中,建议对ArrayList和LinkedList进行性能测试,根据具体场景选择最合适的集合类。
- 并发控制:如果需要在多线程环境中使用List,可以考虑使用CopyOnWriteArrayList或Collections.synchronizedList来保证线程安全。
- 内存优化:对于大数据量的列表,可以考虑使用ArrayList并预先分配足够的容量,避免频繁扩容带来的性能开销。
脑图
觉得不清晰文章顶部有资源可以下载