在 Java 中,最接近“动态数组”概念的是 ArrayList<E>,它是一个可以自动调整大小的数组实现,能够在你添加或删除元素时动态地扩展或收缩。
下面我将从以下几个方面为你详细解释:
- 核心概念:
ArrayList<String> - 基本操作:创建、添加、访问、修改、删除
- 遍历
ArrayList - 常用方法和示例
- 与普通数组的对比
- 注意事项
核心概念:ArrayList<String>
ArrayList:这是 Java 集合框架 (java.util) 中的一个类,它内部使用一个数组来存储元素。<String>:这是泛型 (Generics) 的写法,它告诉ArrayList这个容器只能存储String类型的对象,保证了类型安全,避免了在运行时进行类型转换的麻烦。- 动态:当你向一个已满的
ArrayList添加新元素时,它会自动创建一个更大的新数组,将所有旧元素复制到新数组中,然后将新元素添加进去,这个过程对用户是透明的。
基本操作
a. 创建 ArrayList
首先需要导入 ArrayList 类。
import java.util.ArrayList; // 创建一个空的 String 类型的 ArrayList ArrayList<String> names = new ArrayList<>(); // 也可以在创建时指定初始容量(可选) // ArrayList<String> names = new ArrayList<>(10); // 初始容量为10
b. 添加元素
使用 add() 方法。
names.add("Alice");
names.add("Bob");
names.add("Charlie");
// 在指定位置插入元素
names.add(1, "David"); // 在索引1的位置插入"David",原来的"Bob"及后续元素会后移
System.out.println(names); // 输出: [Alice, David, Bob, Charlie]
c. 访问元素
使用 get() 方法,并通过索引(从 0 开始)来获取元素。
String firstPerson = names.get(0); // 获取第一个元素 "Alice"
String secondPerson = names.get(1); // 获取第二个元素 "David"
System.out.println("The first person is: " + firstPerson);
d. 修改元素
使用 set() 方法,通过索引指定要修改的元素,并提供新的值。
// 将索引为2的元素 "Bob" 修改为 "Bob Jr." names.set(2, "Bob Jr."); System.out.println(names); // 输出: [Alice, David, Bob Jr., Charlie]
e. 删除元素
使用 remove() 方法。
// 通过索引删除元素
names.remove(0); // 删除索引为0的元素 "Alice"
// 通过值删除元素(只删除第一个匹配的)
names.remove("Charlie");
System.out.println(names); // 输出: [David, Bob Jr.]
遍历 ArrayList
有三种常见的方式来遍历 ArrayList。
a. 经典 for 循环 (通过索引)
最传统的方式,适用于需要知道当前索引的场景。
System.out.println("--- Using classic for loop ---");
for (int i = 0; i < names.size(); i++) {
System.out.println("Name at index " + i + ": " + names.get(i));
}
b. for-each 循环 (增强型 for 循环)
最简洁、最常用的方式,当你只需要元素的值,而不关心索引时。
System.out.println("\n--- Using for-each loop ---");
for (String name : names) {
System.out.println("Name: " + name);
}
c. 使用 Iterator
迭代器是 Collection 接口提供的一种标准遍历方式,特别适合在遍历过程中进行删除操作,可以避免 ConcurrentModificationException。
System.out.println("\n--- Using Iterator ---");
// 获取迭代器
java.util.Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
if (name.equals("David")) {
iterator.remove(); // 使用迭代器的remove方法安全地删除元素
}
}
System.out.println("After removing 'David': " + names);
常用方法和示例
这里是一个更完整的示例,展示了更多常用方法。
import java.util.ArrayList;
public class StringArrayListExample {
public static void main(String[] args) {
// 1. 创建
ArrayList<String> fruits = new ArrayList<>();
System.out.println("Initial list: " + fruits);
// 2. 添加
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
System.out.println("After adding: " + fruits);
// 3. 获取大小
System.out.println("Size of the list: " + fruits.size());
// 4. 检查是否包含某个元素
System.out.println("Does the list contain 'Apple'? " + fruits.contains("Apple"));
// 5. 修改
fruits.set(1, "Mango"); // 将 "Banana" 改为 "Mango"
System.out.println("After modification: " + fruits);
// 6. 获取元素
System.out.println("The first fruit is: " + fruits.get(0));
// 7. 删除
fruits.remove("Orange"); // 按值删除
System.out.println("After removing 'Orange': " + fruits);
fruits.remove(0); // 按索引删除
System.out.println("After removing first element: " + fruits);
// 8. 清空列表
fruits.clear();
System.out.println("After clearing the list: " + fruits);
System.out.println("Is the list empty now? " + fruits.isEmpty());
}
}
与普通数组的对比
| 特性 | String[] (普通数组) |
ArrayList<String> (动态数组) |
|---|---|---|
| 大小 | 固定,创建时必须指定大小,之后不能改变。 | 动态,可以自动增长和缩小。 |
| 性能 | 访问 (get) 速度快 (O(1)),增删慢(需要移动元素)。 |
访问 (get) 速度快 (O(1)),增删通常也快,但如果需要扩容则会有性能开销。 |
| 功能 | 功能有限。 | 提供了丰富的方法,如 add(), remove(), size(), contains(), sort() 等。 |
| 语法 | String[] arr = new String[5]; |
ArrayList<String> list = new ArrayList<>(); |
| 类型 | 可以存储不同类型的子类对象(不安全)。 | 通过泛型 (<String>) 强制类型安全,只能存储 String。 |
| 使用场景 | 当你确切知道需要存储多少个元素时,或者性能要求极高且数据量固定时。 | 当你不知道最终会有多少个元素,或者需要频繁增删元素时。绝大多数情况下应优先使用 ArrayList。 |
注意事项
-
不能存储基本数据类型:
ArrayList只能存储对象,如果你想存储int,double等基本类型,必须使用它们的包装类,如Integer,Double。- 正确:
ArrayList<Integer> numbers = new ArrayList<>(); - 错误:
ArrayList<int> numbers = new ArrayList<>();// 编译错误
- 正确:
-
size()vslength:获取ArrayList的大小使用size()方法,而不是数组的length属性。 -
线程安全:
ArrayList是非线程安全 的,如果在多线程环境中使用,可能会出现数据不一致的问题,如果需要线程安全的动态数组,可以使用Vector类(较老)或者Collections.synchronizedList()方法包装ArrayList。
对于 Java 中的 String 动态数组,ArrayList<String> 是你的首选,它灵活、功能强大,并且易于使用,记住它的核心操作:add, get, set, remove, size,并熟练掌握 for-each 循环进行遍历,你就能应对绝大多数关于 String 列表的操作需求。
