一,定义
在Java中,数组是一种基本的数据结构,用来存储固定大小
的同类型元素
序列。
数组的定义有两个关键词:
- ①固定大小,数组是一个容器,这个容器在使用时大小就已经确定了,之后就不能再改变了
- ②同类型元素,容器只能存放同一种类型的元素,在定义数组时要制定元素类型
1,声明数组
声明数组时需指定①元素类型
、②数组名
以及一对标识数组的③中括号[]
:
int[] numbers; // 声明了一个int类型的数组,但未分配内存
此时仅仅在虚拟机栈分配了数组变量,还没有在堆中分配数组的内存空间,数组还不能使用,如果使用未初始化的数组,Idea会提示:
Variable ‘arr1’ might not have been initialized
2,初始化
可以在声明时初始化,也可以先声明后初始化,但使用前一定要完成初始化。
初始化要做两件事情:
- ①虚拟机在堆内存根据数组大小和类型分配一段
连续的内存空间
- ②给每个元素
赋初始值
所以初始化需要指定数组大小或者能根据实际元素数量推断出大小。
初始化可以分为两种:
- 静态初始化
- 动态初始化
2.1 静态初始化
通过列举出数组所有元素,完成初始化,可以不指定数组大小,虚拟机会根据元素数量推断出数组大小,如下面代码,推断数组的大小是3
。
String[] names = new String[]{"Alice", "Bob", "Charlie"}; // 直接初始化字符串数组
也可以简写如下:
String[] names = {"Alice", "Bob", "Charlie"}; // 直接初始化字符串数组
2.2 动态初始化
数组声明时指定数组大小,虚拟机会根据数据类型给元素赋默认值。
int[] numbers = new int[5]; // 声明并创建一个长度为5的int型数组
根据数组元素类型的不同,动态初始化分为两种情况:
- ①对于基本类型的数组,初始化时,按照下表对各元素赋初值:
- ②对于引用类型,如String,元素的默认初始化值是null
2.3 最佳实践
我们一般在声明数组时同时对其进行初始化,以下是集中常见的声明、初始化数组的方式:
//第一种定义数组的方法:
int[] array1 = {1,2,3};//直接赋值(静态初始化)
//int[]是数组的类型,array为数组名,随意取名字
//第二种定义数组的方法:
int[] array2 = new int[]{1,2,3,4};//数组的动态初始化
//第三种定义数组的方法:
int[] array3 = new int[10];//只是分配了内存,但是没有进行赋值,默认值都是0,
//第四种定义数组的方法:
int[] array4;
array = new int[]{1,2,3};//一定要为数组符初值,不然编译器会报错,
二,使用
1,访问与修改元素
数组元素通过索引访问,索引从0开始。
索引可以理解为元素在数组中的序号,不过要注意的是,在计算机中,很多序号是从0开始的,如对于数组int[] arr = {"a","b","c","d","e"}
,各元素的索引如下:
访问或修改元素的语法如下:
- ①通过下表访问元素
System.out.println(names[1]); // 输出第二个元素:"b"
- ②通过下表给数组元素赋值
numbers[0] = 10; // 修改第一个元素为10
2,遍历数组
遍历数组是常见的操作,Java 8引入了forEach循环,使遍历更加简洁:
for (int num : numbers) {
System.out.println(num);
}
或者使用传统for循环:
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}
3,注意事项
- 索引越界:访问不存在的索引(小于0或大于等于数组长度)会导致
ArrayIndexOutOfBoundsException
,这种错误称为“索引越界”。
int[]arr = {1,2,3};
// 上面数组最大索引是2,注意索引是从0开始,下面代码中的索引不在该数组的范围内,会报错
int first = arr[-1];
int last = arr[3];
-
数组长度固定:一旦创建,数组的长度无法更改。若需动态大小,考虑使用ArrayList。
-
空指针异常:未初始化的数组引用调用方法会导致
NullPointerException
。
注意,如果是在方法内部声明的数组变量,未初始化即使用的话,编译时就会报错:Variable ‘arr1’ might not have been initialized。但是把未初始化的数组作为形参传递到数组中,就会出现空指针异常。 -
类型安全:Java数组是类型安全的,只能存放声明时指定类型的对象或基本类型。
三,使用场景
数组广泛应用于多种场景,如:
- 批量数据处理:当需要一次性处理多个相同类型的数据时,数组是理想选择。
- 查找与排序:实现二分查找、冒泡排序等算法。
- 缓存:作为小型数据集合的缓存,提高程序性能。
- 多维数组:模拟矩阵、棋盘等二维结构。
四,实战练习
练习一:数组反转
编写一个函数,接收一个整型数组作为参数,返回一个新数组,其中元素顺序颠倒。
public static int[] reverseArray(int[] nums) {
int[] reversed = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
reversed[i] = nums[nums.length - 1 - i];
}
return reversed;
}
// 测试
int[] original = {1, 2, 3, 4, 5};
int[] reversed = reverseArray(original);
System.out.println(Arrays.toString(reversed)); // 输出:[5, 4, 3, 2, 1]
练习二:数组排序
实现快速排序算法,对整型数组进行排序。
public static void quickSort(int[] arr, int low, int high) {
if (low < high) {
int pivotIndex = partition(arr, low, high);
quickSort(arr, low, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, high);
}
}
private static int partition(int[] arr, int low, int high) {
int pivot = arr[high];
int i = (low - 1);
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
swap(arr, i, j);
}
}
swap(arr, i + 1, high);
return i + 1;
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// 测试
int[] nums = {10, 7, 8, 9, 1, 5};
quickSort(nums, 0, nums.length - 1);
System.out.println(Arrays.toString(nums)); // 输出:[1, 5, 7, 8, 9, 10]