数组在内存中的状态
在开始之前,理解 Java 数组的两个关键点很重要:

- 固定长度:数组一旦被创建,其长度(大小)就不能再改变。
- 引用类型:数组本身是一个对象,它存储的是对其他对象(在这里是 String 对象)的引用,而不是对象本身。
声明并逐个赋值
这是最基础、最直观的方法,首先声明一个数组,然后通过索引为每个元素赋值。
步骤:
- 声明数组:指定数组的类型和名称。
- 创建数组:使用
new关键字为数组分配内存空间,并指定其长度。 - 赋值:通过索引(从 0 开始)为每个数组元素赋值。
代码示例:
public class StringArrayAssignment {
public static void main(String[] args) {
// 1. 声明一个 String 数组
String[] names;
// 2. 创建一个长度为 3 的数组
names = new String[3];
// 3. 通过索引逐个赋值
names[0] = "Alice";
names[1] = "Bob";
names[2] = "Charlie";
// 打印数组内容
System.out.println("数组内容: " + java.util.Arrays.toString(names));
// 输出: 数组内容: [Alice, Bob, Charlie]
}
}
优点:
- 逻辑清晰,易于理解。
- 适用于在运行时动态确定数组长度和内容的情况。
缺点:
- 代码略显冗长。
- 如果忘记为某个元素赋值,该元素将为
null。
声明并初始化(简洁方式)
如果在声明数组时就确定其所有元素,可以使用这种更简洁的语法,Java 会自动根据元素的数量计算数组长度。

代码示例:
public class StringArrayAssignment2 {
public static void main(String[] args) {
// 在一行中完成声明、创建和初始化
String[] fruits = {"Apple", "Banana", "Orange", "Grape"};
// 打印数组内容
System.out.println("水果数组: " + java.util.Arrays.toString(fruits));
// 输出: 水果数组: [Apple, Banana, Orange, Grape]
// 访问单个元素
System.out.println("第一个水果是: " + fruits[0]);
// 输出: 第一个水果是: Apple
}
}
优点:
- 代码非常简洁,可读性高。
- 是在编译时已知所有元素时的首选方法。
缺点:
- 不适用于元素数量或内容在运行时才确定的情况。
使用 Arrays.copyOf() 或 Arrays.copyOfRange()
当你有一个现有的数组,并想基于它创建一个新数组时,这两个方法非常有用。
Arrays.copyOf()
创建一个新数组,其长度可以大于或小于原数组,如果新数组更长,多余的元素会被填充为默认值(对于 String 是 null)。

代码示例:
import java.util.Arrays;
public class StringArrayAssignment3 {
public static void main(String[] args) {
String[] originalColors = {"Red", "Green", "Blue"};
// 复制原数组,新长度为 5
String[] newColors = Arrays.copyOf(originalColors, 5);
System.out.println("新数组: " + Arrays.toString(newColors));
// 输出: 新数组: [Red, Green, Blue, null, null]
// 复制原数组,新长度为 2(只保留前两个元素)
String[] shortColors = Arrays.copyOf(originalColors, 2);
System.out.println("短数组: " + Arrays.toString(shortColors));
// 输出: 短数组: [Red, Green]
}
}
Arrays.copyOfRange()
复制原数组的一个指定范围(从 fromIndex 开始,到 toIndex 结束,但不包含 toIndex)。
代码示例:
import java.util.Arrays;
public class StringArrayAssignment4 {
public static void main(String[] args) {
String[] allDays = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
// 复制索引 2 到 5 的元素 (Wed, Thu, Fri)
String[] weekdays = Arrays.copyOfRange(allDays, 2, 5);
System.out.println("工作日: " + Arrays.toString(weekdays));
// 输出: 工作日: [Wed, Thu, Fri]
}
}
使用 System.arraycopy()
这是一个底层、高性能的数组复制方法,它非常灵活,可以在任意两个数组之间复制元素,甚至可以重叠。
语法:
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
src: 源数组srcPos: 从源数组的哪个位置开始复制dest: 目标数组destPos: 从目标数组的哪个位置开始存放length: 复制多少个元素
代码示例:
import java.util.Arrays;
public class StringArrayAssignment5 {
public static void main(String[] args) {
String[] source = {"A", "B", "C", "D", "E"};
String[] destination = new String[5]; // 必须预先创建好目标数组
// 将 source 数组从索引 1 开始的 3 个元素 ("B", "C", "D")
// 复制到 destination 数组的索引 2 位置
System.arraycopy(source, 1, destination, 2, 3);
System.out.println("目标数组: " + Arrays.toString(destination));
// 输出: 目标数组: [null, null, B, C, D]
}
}
优点:
- 性能极高,是 Java 中最快的数组复制方式之一。
缺点:
- 语法比
Arrays.copyOf()复杂一些,需要手动创建目标数组。
使用 Java 8+ Stream API (高级方式)
对于更复杂的转换和初始化,可以使用 Stream API,这在将一个集合(如 List)转换为数组时特别有用。
代码示例:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StringArrayAssignment6 {
public static void main(String[] args) {
// 1. 从一个 List 创建数组
List<String> nameList = Arrays.asList("David", "Eve", "Frank");
String[] fromList = nameList.toArray(new String[0]);
System.out.println("从 List 创建的数组: " + Arrays.toString(fromList));
// 输出: 从 List 创建的数组: [David, Eve, Frank]
// 2. 使用 Stream 动态生成数组
String[] fromStream = Stream.of("Java", "Python", "C++")
.filter(s -> s.length() > 3)
.toArray(String[]::new);
System.out.println("从 Stream 创建的数组: " + Arrays.toString(fromStream));
// 输出: 从 Stream 创建的数组: [Java, Python]
}
}
总结与最佳实践
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 逐个赋值 | 运行时动态确定内容和长度 | 灵活,逻辑清晰 | 代码冗长,易漏赋值导致 null |
| 声明并初始化 | 编译时已知所有元素 | 最简洁,可读性最高 | 不适用于动态场景 |
Arrays.copyOf() |
基于现有数组创建一个副本或调整大小 | 代码简洁,功能强大 | 需要一个现有数组作为源 |
System.arraycopy() |
高性能复制,需要精确控制复制位置和目标 | 性能最高 | 语法复杂,需手动创建目标数组 |
| Stream API | 复杂转换、从集合转换、动态生成 | 功能强大,表达力强 | 相对复杂,有一定学习成本 |
最佳实践建议:
-
如果所有元素在写代码时都已确定,强烈推荐使用方法二(声明并初始化),因为它最简洁、最安全。
String[] languages = {"Java", "Go", "Rust"}; -
如果需要在运行时动态创建数组是逐步确定的,使用方法一(逐个赋值)。
String[] dynamicArray = new String[10]; for (int i = 0; i < 10; i++) { dynamicArray[i] = "Item-" + i; } -
如果需要复制或调整现有数组的大小,使用
Arrays.copyOf()是最方便的选择。String[] newArray = Arrays.copyOf(oldArray, newLength);
-
在性能极其敏感的代码中,或者需要进行复杂的数组操作时,可以考虑
System.arraycopy()或 Stream API。
