Java 中的 List (ArrayList 、LinkedList 、Vector)
List
List接口常用方法
List集合存储元素特点:有序可重复
List既然是Collection接口的子接口,那么肯定List接口有自己的“特色”方法
以下列出List特有的常用的方法:
-
void add(int index, E element) 将指定的元素插入此列表中的指定位置(可选操作)。
-
Object get(int index)返回此列表中指定位置的元素。
-
int indexOf(Object o) 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
-
int lastIndexOf(Object o) 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
-
Object remove(int index) 删除该列表中指定位置的元素(可选操作)。
-
Object set(int index, E element) 用指定的元素(可选操作)替换此列表中指定位置的元素。
import java.util.*;
/*
* 测试List接口中常用的方法、
* LIst集合存储元素特点:有序可重复
void add(int index, E element) 将指定的元素插入此列表中的指定位置(可选操作)。
Object get(int index)返回此列表中指定位置的元素。
int indexOf(Object o) 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
int lastIndexOf(Object o) 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
Object remove(int index) 删除该列表中指定位置的元素(可选操作)。
Object set(int index, E element) 用指定的元素(可选操作)替换此列表中指定位置的元素。
* */
public class ListTest01 {
public static void main(String[] args) {
//创建List类型的集合
// List myList = new LinkedList();
// List myList = new Vector();
List myList = new ArrayList();
myList.add("A");
myList.add("B");
myList.add("C");
myList.add("D");
// 在列表指定位置插入元素
// 这个方法使用的不多,对于ArrayList来说效率比较低
myList.add(1,"king");
Iterator it = myList.iterator();
while(it.hasNext()){
Object elt = it.next();
System.out.println(elt);
}
//根据下表获取元素
Object firstObj = myList.get(0);
System.out.println(firstObj);
// 通过下标遍历 [List集合特有的方式,Set没有]
for (int i = 0; i < myList.size(); i++) {
Object obj = myList.get(i);
System.out.println(obj);
}
}
}
ArrayList
- ArrayList集合初始化容量是10
- ArrayList集合底层是Object类型的数组 Object []
- ArrayList集合的扩容:原容量的1.5倍
- ArrayList底层是数组,怎么优化?
尽可能少的扩容,因为数组扩容的效率比较低,建议在使用ArrayList集合的时候,预估元素的个数,给定一个初始化容量 - 数组的优点:检索效率比较高(每个元素占用空间大小相同,内存地址是连续的 ,知道首元素的内存地址,知道下标,我们就可以计算元素的内存地址,所以检索效率最高)
- 数组的缺点:随机增删效率比较低,很难存储大数据量(很难找到一块非常巨大的连续的内存空间)
- 向数组末尾添加元素效率还是比较高的
- 面试官经常问的一个问题: 这么多集合中,你使用的哪个数组最多?
ArrayList集合,因为往数组末尾添加元素,效率不受影响,另外我们检索/查找某个元素的操作比较多
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
/*
*ArrayList集合的扩容:原容量的1.5倍
* ArrayList底层是数组,怎么优化?
* 尽可能少的扩容,因为数组扩容的效率比较低,建议在使用ArrayList集合的时候,预估元素的个数,给定一个初始化容量
* 数组的优点:检索效率比较高(每个元素占用空间大小相同,内存地址是连续的 ,知道首元素的内存地址,知道下标,我们就可以计算元素的内存地址,所以检索效率最高)
* 数组的缺点:随机增删效率比较低,很难存储大数据量(很难找到一块非常巨大的连续的内存空间)
* 向数组末尾添加元素效率还是比较高的
* 面试官经常问的一个问题: 这么多集合中,你使用的哪个数组最多?
* ArrayList集合,因为往数组末尾添加元素,效率不受影响,另外我们检索/查找某个元素的操作比较多
* */
public class ArrayListTest01 {
public static void main(String[] args) {
//默认初始化容量是10 (底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量是10)
//数组的长度是10
List list1 = new ArrayList();
//集合的size()方法是获得当前集合中元素的个数,不是获取集合的容量。
System.out.println(list1.size()); //0
List list2 = new ArrayList(20);
System.out.println(list2.size()); //0
list1.add(1);
list1.add(1);
list1.add(1);
list1.add(1);
list1.add(1);
list1.add(1);
list1.add(1);
list1.add(1);
list1.add(1);
list1.add(1);
System.out.println(list1.size());
//再加一个元素
list1.add(10);
//新的容量增长1.5倍
System.out.println(list1);
//创建一个HashSet集合
Collection c = new HashSet();
c.add(100);
c.add(50);
c.add(66);
c.add(610);
c.add(100);
//通过这个构造方法就可以将HashSet集合转化为ArrayList集合。
List myList3 = new ArrayList(c);
for (int i = 0; i < myList3.size(); i++) {
System.out.println(myList3.get(i));
}
}
}
LinkedList链表
- 单链表中的节点
- 节点是单向链表的基本单元
链表优点:随机增删效率比较高(不需要大量数据进行位移)
链表缺点:查询效率比较低
import java.util.LinkedList;
import java.util.List;
/*
* 单链表中的节点
* 节点是单向链表的基本单元
* 链表的元素在空间存储上内存地址不连续
* 链表优点:随机增删效率比较高(不需要大量数据进行位移)
* 链表缺点:查询效率比较低
* */
public class LinkedListTest {
public static void main(String[] args) {
// LinkedList集合底层也有下标的
// 注意:ArrayList之所以检索效率比较高,是因为底层数组发挥的作用、
// LinkedList集合也有下标,但是检索/查找某个元素的时候效率比较低,因为只能从头节点开始一个个遍历
List list = new LinkedList();
list.add("a");
list.add("b");
list.add("c");
for (int i = 0; i < list.size(); i++) {
Object obj = list.get(i);
System.out.println(obj);
}
}
}
-
LinkedList集合是双向的链表
-
链表的元素在空间存储上内存地址不连续
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class LinkedListTest02 {
public static void main(String[] args) {
//LinkedList集合中有初始化容量吗? 没有。
//最初这个链表中没有任何元素。first和Last 引用都是null
// 不管是LinkedList还是ArrayList,以后写代码不需要关心具体是哪个集合
// 因为我们要面向接口编程,调用的方法都是接口中的方法。
// List list2 = new ArrayList(); // 这样写表示底层使用的数组
List list2 = new LinkedList(); // 这样写表示底层使用的双向链表
// 以下的方法都是面向的接口编程
list2.add("abc");
list2.add("456");
list2.add("789");
for (int i = 0; i < list2.size(); i++) {
System.out.println(list2.get(i));
}
}
}
Vector
Vector:
-
底层是一个数组
-
初始化容量是10
-
怎么扩容的?
扩容之后是原容量的二倍。 -
ArrayList扩容后是之前的1.5倍
-
Vector中所有的方法都是线程同步的,都带有synchronized 关键字 ,
是线程安全的,效率比较低,使用较少 -
怎么将一个线程不安全的ArrayList集合转换成线程安全的?
使用集合工具类: java.util.Collections;- java.util.Collections;是集合工具类
- java.util.Collection; 是集合接口
import java.util.*;
/*
* Vector:
* 底层是一个数组
* 初始化容量是10
* 怎么扩容的?
* 扩容之后是原容量的二倍。
* ArrayList扩容后是之前的1.5倍
* Vector中所有的方法都是线程同步的,都带有synchronized 关键字 ,
* 是线程安全的,效率比较低,使用较少
* 怎么将一个线程不安全的ArrayList集合转换成线程安全的?
使用集合工具类:
* java.util.Collections;
*
* java.util.Collections;是集合工具类
* java.util.Collection; 是集合接口 */
public class VectorTest {
public static void main(String[] args) {
Vector vec = new Vector();
vec.add(1);
vec.add(1);
vec.add(1);
vec.add(1);
vec.add(1);
vec.add(1);
vec.add(1);
vec.add(1);
vec.add(1);
vec.add(1);
// 满了容量之后进行扩容,扩容直接扩成两倍
vec.add(11);
Iterator it = vec.iterator();
while(it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
for (int i = 0; i < vec.size(); i++) {
System.out.println(vec.get(i));
}
// 这个可能以后要使用!!!
List myList = new ArrayList(); //非线程安全的
// 变成线程安全的
Collections.synchronizedList(myList);//这里没有办法看效果,还没学多线程,先记住!
// myList集合现在是线程安全的了
myList.add("111");
myList.add("222");
myList.add("333");
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤