Java 中的 ArrayList
是一个非常常用的动态数组,它属于 Java 集合框架的一部分。与普通数组不同,ArrayList
可以在需要时动态调整其大小。以下是 ArrayList
的一些详细介绍:
基本特性
- 动态大小 :
ArrayList
会自动调整其大小以适应新元素。 - 有序集合:元素按插入顺序存储,但可以通过索引访问。
- 允许重复:可以包含重复的元素。
- 允许空值 :可以包含
null
值。 - 非线程安全:在多线程环境下使用时需要手动同步。
常用方法
-
创建 ArrayList
javaArrayList<String> list = new ArrayList<>();
-
添加元素
-
添加单个元素:
add(E e)
javalist.add("apple");
-
在指定位置添加:
add(int index, E element)
javalist.add(1, "banana");
-
-
访问元素
-
通过索引:
get(int index)
javaString fruit = list.get(0);
-
-
修改元素
-
修改元素值:
set(int index, E element)
javalist.set(1, "orange");
-
-
删除元素
-
通过索引删除:
remove(int index)
javalist.remove(0);
-
通过值删除(第一个匹配的元素):
remove(Object o)
javalist.remove("banana");
-
-
遍历元素
javafor (String item : list) { System.out.println(item); }
-
其他常用方法
- 获取大小 :
size()
- 检查是否为空 :
isEmpty()
- 清空列表 :
clear()
- 检查是否包含指定元素 :
contains(Object o)
- 获取元素索引 :
indexOf(Object o)
- 获取大小 :
性能注意事项
- 时间复杂度 :
- 添加/修改/获取元素:
O(1)
(平均情况) - 在中间插入/删除元素:
O(n)
- 添加/修改/获取元素:
- 由于
ArrayList
是基于数组实现的,当超过初始容量时,可能需要重新分配数组,这会涉及原数组到新数组的复制。
使用示例
java
import java.util.ArrayList;
public class ArrayListExample {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
// 添加元素
list.add("apple");
list.add("banana");
list.add("cherry");
// 插入元素
list.add(1, "orange");
// 访问和修改元素
String fruit = list.get(0);
list.set(1, "kiwi");
// 删除元素
list.remove("banana");
// 输出列表
for (String item : list) {
System.out.println(item);
}
}
}
ArrayList
是适用于频繁访问和修改的场景,但在性能和安全性要求较高的情况下,选择其他集合(如 LinkedList
或同步列表)可能更为合适。
是的, ArrayList
只能存储引用数据类型 ,不能直接存储基本数据类型(如 int
、double
、char
等)。这是因为 ArrayList
是基于 Java 的泛型实现的,而泛型只支持对象类型(引用类型),不支持基本数据类型。
如何存储基本数据类型?
虽然 ArrayList
不能直接存储基本数据类型,但 Java 提供了自动装箱(Autoboxing)机制,可以将基本数据类型自动转换为对应的包装类,使其间接存储基本数据类型。
常见的基本数据类型及其对应的包装类
基本数据类型 | 包装类(引用类型) |
---|---|
int |
Integer |
double |
Double |
char |
Character |
boolean |
Boolean |
float |
Float |
long |
Long |
short |
Short |
byte |
Byte |
示例:
java
ArrayList<Integer> intList = new ArrayList<>();
intList.add(10); // 自动装箱,将 int 转为 Integer
intList.add(20);
intList.add(30);
System.out.println(intList); // 输出: [10, 20, 30]
在这个例子中,10
、20
和 30
是 int
类型的数据,但 Java 自动将它们转换为 Integer
(包装类)对象,并存入了 ArrayList
。
取值时自动拆箱
存储在 ArrayList
中的包装类对象,在需要时会自动转换回基本数据类型(称为"拆箱")。
示例:
java
int sum = 0;
for (int num : intList) { // 自动拆箱,将 Integer 转为 int
sum += num;
}
System.out.println("总和:" + sum);
注意事项
-
性能
- 自动装箱和拆箱虽然使用方便,但它会增加一定的性能开销,尤其是频繁操作时。
-
避免空指针异常
-
如果
ArrayList
中的某个元素为null
,在拆箱时会抛出NullPointerException
。 -
例如:
javaArrayList<Integer> intList = new ArrayList<>(); intList.add(null); // 添加了一个 null int num = intList.get(0); // 自动拆箱时抛出 NullPointerException
-
如果需要存储多个不同的基本数据类型?
如果你的 ArrayList
需要同时存储多种基本数据类型,可以考虑以下几种方式:
-
使用
ArrayList<Object>
-
通过手动装箱,将数据都存储为对应的包装类,然后将它们存入一个
ArrayList<Object>
中。 -
示例:
javaArrayList<Object> list = new ArrayList<>(); list.add(123); // 存储 Integer list.add(45.67); // 存储 Double list.add("Hello"); // 存储 String list.add(true); // 存储 Boolean for (Object obj : list) { System.out.println(obj.toString()); }
-
-
使用自定义类进行封装
-
自定义一个类,把所有需要的数据类型存为类的字段。
-
示例:
javaclass Data { int intValue; double doubleValue; String stringValue; Data(int intValue, double doubleValue, String stringValue) { this.intValue = intValue; this.doubleValue = doubleValue; this.stringValue = stringValue; } } ArrayList<Data> dataList = new ArrayList<>(); dataList.add(new Data(10, 20.5, "Hello")); for (Data data : dataList) { System.out.println(data.intValue + ", " + data.doubleValue + ", " + data.stringValue); }
-
-
使用
Map
或其他集合结构- 可以使用
Map<String, Object>
或类似的容器,按键值对存储不同类型的数据。
- 可以使用
总结
ArrayList
只能直接存储引用类型。- 如果要存储基本数据类型,可以通过包装类实现,依赖于自动装箱和拆箱机制。
- 对于需要混合存储多种类型的数据,可以使用
ArrayList<Object>
或自定义类、Map
等其他结构。-