引用 vs. 值
首先要理解,Java 中的 List 是一个对象,它存储的是对对象的引用(reference),而不是对象本身,当我们“赋值”一个 List 时,我们通常是在操作它的引用。

创建一个新的 List 并赋值(最常见)
这是最基本的需求,创建一个 List 实例并给它赋一些初始值。
方法1:使用 List.of() (Java 9+ 推荐)
这是现代 Java(9及以上版本)中最推荐的方法,它创建一个不可变的 List。
import java.util.List;
// 创建一个包含3个字符串的不可变List
List<String> names = List.of("Alice", "Bob", "Charlie");
// 尝试修改会抛出 UnsupportedOperationException
// names.add("David"); // 这行代码会编译失败,运行时抛出异常
优点:
- 简洁:代码非常简洁明了。
- 安全:创建后不能被修改,可以有效防止意外修改,特别适合作为方法的返回值或配置数据。
- 性能:底层可能使用更高效的实现。
方法2:使用 Arrays.asList() (经典方法)
创建一个固定大小的 List,这个 List 是可变的,但不能改变其大小(不能添加或删除元素)。

import java.util.Arrays; import java.util.List; // 创建一个包含3个整数的List,大小固定 List<Integer> numbers = Arrays.asList(1, 2, 3); // 可以修改元素 numbers.set(0, 10); // 将第一个元素改为10,这是允许的 System.out.println(numbers); // 输出: [10, 2, 3] // 不能添加或删除元素 // numbers.add(4); // 这行代码会抛出 UnsupportedOperationException // numbers.remove(0); // 这行代码也会抛出 UnsupportedOperationException
优点:
- 兼容旧版 Java(Java 5+)。
- 适用于需要修改内容但不改变大小的场景。
方法3:使用 new ArrayList<>() 并手动添加 (最灵活)
这是最传统、最灵活的方法,创建一个可变大小的 ArrayList,可以自由地添加、删除、修改元素。
import java.util.ArrayList;
import java.util.List;
// 创建一个空的ArrayList
List<String> fruits = new ArrayList<>();
// 添加元素
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
System.out.println(fruits); // 输出: [Apple, Banana, Orange]
// 修改元素
fruits.set(1, "Mango");
System.out.println(fruits); // 输出: [Apple, Mango, Orange]
// 删除元素
fruits.remove("Apple");
System.out.println(fruits); // 输出: [Mango, Orange]
优点:
- 完全可变:可以随时修改列表的大小和内容。
- 通用:适用于所有需要动态列表的场景。
将一个 List 的内容复制到另一个 List
这是另一个非常常见的场景,这里最容易出错。

错误的做法:直接赋值引用
List<String> originalList = new ArrayList<>(Arrays.asList("A", "B"));
List<String> copiedList = originalList; // 这不是复制,是引用赋值
// 修改 copiedList
copiedList.add("C");
// 查看 originalList,你会发现它也被修改了!
System.out.println("Original List: " + originalList); // 输出: [A, B, C]
System.out.println("Copied List: " + copiedList); // 输出: [A, B, C]
copiedList 和 originalList 实际上是同一个对象,修改任何一个都会影响另一个。
正确的做法:复制内容
方法1:使用构造函数(推荐,浅拷贝)
这是最常用且高效的方法,它会创建一个新的 ArrayList 对象,并将原列表中的所有元素引用复制到新列表中。
List<String> originalList = new ArrayList<>(Arrays.asList("A", "B"));
// 使用 ArrayList 的构造函数创建一个新列表
List<String> copiedList = new ArrayList<>(originalList);
// 修改 copiedList
copiedList.add("C");
// originalList 保持不变
System.out.println("Original List: " + originalList); // 输出: [A, B]
System.out.println("Copied List: " + copiedList); // 输出: [A, B, C]
注意:这是浅拷贝,如果列表中的元素是对象(如 User, Product),那么新列表和原列表中的元素引用是同一个,修改其中一个列表中的对象,另一个列表中的对象也会被修改,如果需要深拷贝,需要手动实现。
方法2:使用 addAll() 方法
List<String> originalList = new ArrayList<>(Arrays.asList("A", "B"));
List<String> copiedList = new ArrayList<>(); // 先创建一个空列表
copiedList.addAll(originalList); // 然后将所有元素添加进去
// 效果和方法1一样
方法3:使用 Java 8+ 的 Stream (函数式风格)
List<String> originalList = new ArrayList<>(Arrays.asList("A", "B"));
List<String> copiedList = originalList.stream().collect(Collectors.toList());
// 效果和方法1一样
为现有 List 重新赋值(替换整个列表)
如果你想用一个全新的列表替换掉一个已有的列表引用,你需要操作的是持有列表引用的变量。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ListReassignment {
public static void main(String[] args) {
List<String> myList = new ArrayList<>(Arrays.asList("Old", "Values"));
System.out.println("Before reassignment: " + myList);
// 创建一个全新的列表
List<String> newList = Arrays.asList("New", "Values");
// 将 myList 这个变量指向一个全新的对象
myList = newList; // myList 不再指向原来的列表,而是指向 newList
System.out.println("After reassignment: " + myList);
}
}
输出:
Before reassignment: [Old, Values]
After reassignment: [New, Values]
重要提示:如果这个 myList 是作为方法的参数传入的,这种重新赋值不会影响调用方传入的变量,因为 Java 是值传递,传递的是引用的副本。
public class ListReassignmentTest {
public static void main(String[] args) {
List<String> myCallerList = new ArrayList<>(Arrays.asList("Initial"));
System.out.println("Before method call: " + myCallerList);
reassignList(myCallerList);
System.out.println("After method call: " + myCallerList); // myCallerList 仍然是 "Initial"
}
public static void reassignList(List<String> listParam) {
// 这里的 listParam 是 myCallerList 的一个引用副本
listParam = Arrays.asList("New"); // 修改的是副本,不影响 myCallerList
}
}
总结与最佳实践
| 需求 | 推荐方法 | 说明 |
|---|---|---|
| 创建不可变列表 | List.of(...) |
Java 9+,简洁、安全。 |
| 创建固定大小可变列表 | Arrays.asList(...) |
不能增删,只能改。 |
| 创建完全可变列表 | new ArrayList<>(...) |
最灵活,可自由增删改。 |
| 复制列表内容 | new ArrayList<>(originalList) |
首选方法,创建新对象,避免引用问题。 |
| 替换整个列表引用 | myList = newList; |
直接操作变量,使其指向新对象。 |
记住关键点:
- 区分赋值和复制:直接赋值是传递引用,复制是创建新对象。
- 理解浅拷贝:
new ArrayList<>(...)和addAll()都是浅拷贝,对于对象元素,它们共享引用。 - 明确需求:根据你是否需要修改列表、修改列表大小,来选择最合适的创建方式。
