数组是Java中最基础且重要的数据结构之一,它本质上是一组相同类型数据的线性集合。与普通变量只能存储单个值不同,数组允许我们在单个变量名下存储多个值,并通过索引(下标)来访问各个元素。
当我们在Java中声明一个数组时,JVM会在堆内存中分配一块连续的空间。这块内存空间的大小取决于数组的类型和长度。例如,一个长度为10的int数组会占用40字节的连续内存空间(假设int占4字节)。
数组变量本身存储的是这块内存区域的首地址(引用),而不是实际的数据内容。这就是为什么我们打印数组变量时(如System.out.println(nums))会看到类似"[I@1b6d3586"的地址信息,而不是数组内容。
注意:数组一旦创建,其长度就固定不变。这是数组与集合类(如ArrayList)的重要区别之一。
Java为数组元素提供了默认初始化值,具体取决于数组类型:
这个特性在实际开发中非常有用,例如:
java复制int[] scores = new int[30]; // 自动初始化为全0数组
String[] names = new String[10]; // 自动初始化为全null数组
这是最基础的数组创建方式,分为四个明确步骤:
java复制// 1. 声明
double[] prices;
// 2. 分配空间
prices = new double[5];
// 3. 赋值
prices[0] = 3.99;
prices[1] = 5.99;
// 4. 使用
System.out.println(prices[0]);
这种方式的优点是步骤清晰,适合在需要先声明数组后初始化的情况。缺点是代码略显冗长。
将声明和空间分配合并为一行,是更常见的写法:
java复制// 合并写法
char[] vowels = new char[5];
vowels[0] = 'a';
vowels[1] = 'e';
这种写法减少了代码行数,但保留了显式的空间分配过程。特别适合数组长度需要动态计算的情况:
java复制int size = calculateSize(); // 假设这是个计算方法
String[] items = new String[size];
当数组元素已知时,可以使用最简洁的初始化方式:
java复制// 完整写法
int[] primes = new int[]{2, 3, 5, 7, 11};
// 简写形式(最常用)
int[] primes = {2, 3, 5, 7, 11};
简写形式的注意事项:
错误示例:
java复制int[] nums;
nums = {1, 2, 3}; // 编译错误
传统for循环通过索引访问数组元素,是最灵活的遍历方式:
java复制int[] fib = {1, 1, 2, 3, 5, 8};
for (int i = 0; i < fib.length; i++) {
System.out.println("第" + (i+1) + "个元素:" + fib[i]);
}
关键点:
i < array.length而不是i <= array.length - 1,更简洁length属性获取,不是方法调用for (int i = array.length - 1; i >= 0; i--)增强for循环是Java 5引入的语法糖,专门为集合遍历设计:
java复制String[] languages = {"Java", "Python", "C++"};
for (String lang : languages) {
System.out.println(lang);
}
特点:
实际开发中选择建议:只需要读取元素值时用for-each,需要索引或修改数组时用传统for。
查找数组最大值/最小值是经典算法问题,核心思路是:
java复制// 最大值查找
int findMax(int[] arr) {
if (arr == null || arr.length == 0) {
throw new IllegalArgumentException("数组不能为空");
}
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
优化技巧:
数值数组的求和是基础但常用的操作:
java复制double calculateAverage(int[] nums) {
if (nums == null || nums.length == 0) return 0;
double sum = 0;
for (int num : nums) {
sum += num;
}
return sum / nums.length;
}
注意事项:
线性查找是最直接的查找方式:
java复制int indexOf(String[] arr, String target) {
for (int i = 0; i < arr.length; i++) {
if (target.equals(arr[i])) {
return i;
}
}
return -1; // 未找到
}
对于已排序数组,可以使用更高效的二分查找(时间复杂度O(log n))。
在有序数组中插入元素并保持顺序,需要以下步骤:
java复制int[] insert(int[] sortedArr, int newElement) {
int[] newArr = new int[sortedArr.length + 1];
System.arraycopy(sortedArr, 0, newArr, 0, sortedArr.length);
int insertPos = newArr.length - 1; // 默认插入末尾
for (int i = 0; i < sortedArr.length; i++) {
if (newElement < sortedArr[i]) {
insertPos = i;
break;
}
}
// 后移元素
for (int i = newArr.length - 1; i > insertPos; i--) {
newArr[i] = newArr[i - 1];
}
newArr[insertPos] = newElement;
return newArr;
}
删除元素的逻辑与插入类似:
java复制int[] remove(int[] arr, int index) {
if (index < 0 || index >= arr.length) {
throw new IndexOutOfBoundsException("无效索引");
}
int[] newArr = new int[arr.length - 1];
System.arraycopy(arr, 0, newArr, 0, index);
System.arraycopy(arr, index + 1, newArr, index, arr.length - index - 1);
return newArr;
}
实际开发中,频繁插入/删除操作应考虑使用ArrayList等动态集合。
二维数组是数组的数组,常用于表示表格数据:
java复制// 三种初始化方式
int[][] matrix1 = new int[3][4]; // 3行4列
int[][] matrix2 = {{1,2}, {3,4}}; // 2x2矩阵
int[][] matrix3 = new int[3][]; // 不规则数组
matrix3[0] = new int[2];
matrix3[1] = new int[3];
遍历二维数组通常需要嵌套循环:
java复制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();
}
Java支持每行长度不同的不规则数组:
java复制int[][] triangle = new int[3][];
triangle[0] = new int[1];
triangle[1] = new int[2];
triangle[2] = new int[3];
这种结构适合存储像三角形数字这样的不规则数据。
Java提供了Arrays工具类,包含各种数组操作方法:
java复制import java.util.Arrays;
// 排序
int[] nums = {3,1,4,2};
Arrays.sort(nums); // [1,2,3,4]
// 二分查找(必须先排序)
int index = Arrays.binarySearch(nums, 3);
// 数组转字符串
String str = Arrays.toString(nums);
// 数组填充
Arrays.fill(nums, 0); // 全填充为0
// 数组比较
boolean equal = Arrays.equals(arr1, arr2);
// 数组复制
int[] copy = Arrays.copyOf(original, newLength);
这些方法封装了常见操作,能显著减少样板代码。但要注意:
数组作为Java的基础数据结构,掌握其特性和操作技巧是每个Java开发者的必备技能。从简单的存储容器到复杂的算法实现,数组都扮演着重要角色。理解这些核心概念后,可以更高效地处理各种数据操作任务。