Java数组(超详细)_java 数组
Java 数组是用于存储固定长度、相同类型元素的容器,是 Java 中最基本的数据结构之一。数组在内存中连续存储,提供了高效的随机访问能力。以下是对 Java 数组的超详细讲解,涵盖定义、创建、操作、常见用法、注意事项及最佳实践,帮助你全面掌握 Java 数组的使用。
一、Java 数组概述
1. 什么是数组?
- 定义:数组是一组固定长度的、相同类型的元素集合,存储在连续的内存块中。
- 特点:
- 固定长度:创建后长度不可变。
- 类型安全:所有元素必须是同一类型(基本类型或引用类型)。
- 索引访问:通过下标(从 0 开始)访问元素,效率高(O(1))。
- 用途:
- 存储一组数据(如成绩列表、对象集合)。
- 作为方法参数或返回值。
- 基础数据结构,支持算法实现(如排序、查找)。
2. 数组的优缺点
- 优点:
- 快速随机访问(通过索引)。
- 内存分配连续,适合高性能场景。
- 实现简单,适合固定大小的数据集合。
- 缺点:
- 长度固定,无法动态扩展(可使用
ArrayList
替代)。 - 插入和删除效率低(需移动元素)。
- 不支持复杂操作(如自动排序、查找)。
二、数组的定义与创建
1. 声明数组
数组声明指定元素类型和变量名:
type[] arrayName; // 推荐写法
type arrayName[]; // C 风格,不推荐
- 示例:
int[] numbers; // 整型数组
String[] names; // 字符串数组
double[][] matrix; // 二维数组
2. 创建数组
使用 new
关键字分配内存:
arrayName = new type[length];
- 示例:
int[] numbers = new int[5]; // 创建长度为 5 的整型数组
- 默认值:
- 基本类型:
int
(0)、double
(0.0)、boolean
(false)等。 - 引用类型:
null
。
3. 初始化数组
- 静态初始化:声明时直接赋值。
int[] numbers = {1, 2, 3, 4, 5};
String[] names = new String[]{"Alice", "Bob", "Charlie"};
- 动态初始化:创建后逐个赋值。
int[] numbers = new int[3];
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;
4. 二维数组
- 定义:数组的元素是数组(矩阵)。
- 示例:
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
三、数组的基本操作
1. 访问元素
通过索引访问,索引从 0
到 length - 1
:
int[] arr = {10, 20, 30};
System.out.println(arr[0]); // 输出:10
arr[1] = 25; // 修改元素
2. 获取数组长度
使用 length
属性:
int[] arr = new int[5];
System.out.println(arr.length); // 输出:5
3. 遍历数组
- for 循环:
int[] arr = {1, 2, 3};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
- 增强 for 循环(for-each):
for (int num : arr) {
System.out.println(num);
}
4. 二维数组遍历
int[][] matrix = {{1, 2}, {3, 4}, {5, 6}};
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
// 输出:
// 1 2
// 3 4
// 5 6
5. 数组复制
- 手动复制:
int[] src = {1, 2, 3};
int[] dest = new int[src.length];
for (int i = 0; i < src.length; i++) {
dest[i] = src[i];
}
- 使用
System.arraycopy
:
int[] dest = new int[src.length];
System.arraycopy(src, 0, dest, 0, src.length);
- 使用
Arrays.copyOf
:
import java.util.Arrays;
int[] dest = Arrays.copyOf(src, src.length);
四、常见操作与工具类(java.util.Arrays
)
java.util.Arrays
提供了丰富的数组操作方法。
1. 排序
import java.util.Arrays;
int[] arr = {5, 2, 8, 1, 9};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); // 输出:[1, 2, 5, 8, 9]
2. 查找(二分查找)
数组需先排序:
int index = Arrays.binarySearch(arr, 5);
System.out.println(index); // 输出:2(元素 5 的索引)
3. 填充
int[] arr = new int[5];
Arrays.fill(arr, 10);
System.out.println(Arrays.toString(arr)); // 输出:[10, 10, 10, 10, 10]
4. 比较
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
boolean equal = Arrays.equals(arr1, arr2);
System.out.println(equal); // 输出:true
5. 转换为字符串
int[] arr = {1, 2, 3};
System.out.println(Arrays.toString(arr)); // 输出:[1, 2, 3]
五、数组的高级用法
1. 多维数组
- 不规则二维数组:
int[][] irregular = new int[3][];
irregular[0] = new int[2];
irregular[1] = new int[3];
irregular[2] = new int[1];
2. 数组作为参数
void printArray(int[] arr) {
for (int num : arr) {
System.out.print(num + " ");
}
}
int[] arr = {1, 2, 3};
printArray(arr); // 输出:1 2 3
3. 数组作为返回值
int[] getNumbers() {
return new int[]{1, 2, 3};
}
int[] result = getNumbers();
System.out.println(Arrays.toString(result)); // 输出:[1, 2, 3]
4. 动态数组(使用 ArrayList
)
当需要动态长度时,使用 java.util.ArrayList
:
import java.util.ArrayList;
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
System.out.println(list); // 输出:[1, 2]
六、注意事项
- 数组越界:
- 访问超出
length - 1
的索引会抛出ArrayIndexOutOfBoundsException
。 - 示例:
java int[] arr = new int[3]; System.out.println(arr[3]); // 错误:越界
- 初始化默认值:
- 基本类型数组初始化为 0、false 等。
- 引用类型数组初始化为
null
,需手动分配对象。
- 引用类型数组:
- 数组存储对象引用而非对象本身。
String[] names = new String[2];
names[0] = new String("Alice");
- 性能考虑:
- 数组适合固定长度、频繁访问的场景。
- 动态长度场景使用
ArrayList
。
- 多维数组内存:
- Java 的多维数组是“数组的数组”,非规则矩阵可能导致内存不连续。
七、最佳实践
- 初始化时指定大小:
- 避免未初始化数组导致
NullPointerException
。
int[] arr = new int[5]; // 正确
int[] arr; // 错误:未初始化
- 使用
Arrays
工具类:
- 简化排序、查找、复制等操作。
Arrays.sort(arr);
- 优先选择
for-each
:
- 遍历数组时,
for-each
更简洁且不易出错。
for (int num : arr) { ... }
- 避免手动复制:
- 使用
Arrays.copyOf
或System.arraycopy
提高效率。
- 动态需求用
ArrayList
:
- 当数组长度不确定时,优先使用
ArrayList
。
ArrayList<Integer> list = new ArrayList<>();
- 边界检查:
- 访问数组前检查索引。
if (index >= 0 && index < arr.length) {
arr[index] = value;
}
八、常见问题与解决
- 问题:数组越界异常
- 原因:访问非法索引。
- 解决:检查索引范围,使用
arr.length
。
- 问题:数组初始化为
null
- 原因:仅声明未分配内存。
- 解决:使用
new
或静态初始化。
int[] arr = new int[5]; // 正确
- 问题:多维数组操作复杂
- 原因:不规则数组长度不一。
- 解决:确保规则矩阵,或使用
ArrayList<List<T>>
。
- 问题:性能瓶颈
- 原因:频繁插入或删除。
- 解决:改用
ArrayList
或其他动态数据结构。
九、总结
Java 数组是高效、简单的固定长度数据结构,适合存储和访问同类型元素。支持一维和多维数组,提供 length
属性和 Arrays
工具类简化操作。掌握数组的创建、遍历、复制及常见方法(如排序、查找),并结合 ArrayList
解决动态需求,能满足大多数开发场景。遵循最佳实践(如边界检查、使用工具类),可提高代码可靠性和性能。
如果需要更深入的示例(如数组在算法中的应用、性能优化)或特定场景的代码,请告诉我!