本文纲要
- 数组介绍
- 数组定义格式
- 数组动态初始化
- 数组元素访问
- Java内存分配与数组内存图
- 两个数组内存图
- 多个数组指向相同内存
- 数组静态初始化
- 数组操作常见问题
- 数组遍历
- 数组获取最大值
- 数组元素求和
- 数组基本查找
- 评委打分案例
数组介绍
数组(Array)是一种容器,用来存储同种数据类型的多个值。与普通变量只能存储单个值不同,数组可以一次存储多个同类型数据,并通过索引访问每一个元素。
数组的典型使用场景:当需要操作一组数据时,例如统计多个班级的成绩、存储多个用户输入等,就可以用数组把这组数据整体管理起来,而不是定义大量零散的变量。
数组定义格式
Java中定义数组有两种格式:
// 格式1:数据类型[] 数组名;
int[] arr;
// 格式2:数据类型 数组名[];
int arr2[];
格式1使用最普遍,推荐使用。格式2也能定义数组,但较少见。
这两种方式只是定义了一个数组类型的变量,此时还没有实际的数组容器,不能直接使用。
数组动态初始化
1 ) 概念
动态初始化:在创建数组时只指定长度,系统自动为数组元素分配默认值。
2 ) 格式
数据类型[] 数组名 = new 数据类型[数组长度];
示例:
int[] arr = new int[5]; // 可以存储5个int型整数
byte[] bArr = new byte[3]; // 可以存储3个byte型整数
new关键字负责在堆内存中开辟数组空间,并返回内存地址给数组变量。
3 ) 打印数组名
打印数组名时,看到的是内存地址,例如 [I@10f87f48
解读:
@:分隔符[:表示数组类型I:表示存储的数据类型(int)10f87f48:十六进制内存地址
数组元素访问
1 ) 访问格式
数组名[索引]
索引是数组元素在容器中的编号,从0开始,连续递增。例如长度为3的数组,索引为0、1、2。
2 ) 存取操作
- 取值:
arr[0] - 存值:
arr[0] = 11
动态初始化后,即使没有赋值,元素也能取出,此时取出的都是默认值
不同类型默认值如下:
| 数组类型 | 默认值 |
|---|---|
| 整数类型 | 0 |
| 浮点类型 | 0.0 |
| 布尔类型 | false |
| 字符类型 | 空字符(‘\u0000’) |
| 引用类型 | null |
示例代码
int[] arr = new int[3];
System.out.println(arr[0]); // 0
System.out.println(arr[1]); // 0
System.out.println(arr[2]); // 0
arr[0] = 11;
arr[1] = 22;
arr[2] = 33;
System.out.println(arr[0]); // 11
System.out.println(arr[1]); // 22
System.out.println(arr[2]); // 33
Java内存分配与数组内存图
Java程序运行时,内存主要划分为以下几块区域:
- 栈(Stack):方法运行时进入的内存,局部变量存放在这里。
- 堆(Heap):new出来的内容存放于此,都有地址值。
- 方法区(Method Area):字节码文件(.class)加载时进入的内存。
1 ) 单数组内存图
以如下代码为例:
int[] arr = new int[3];
arr[0] = 11;
arr[1] = 22;
arr[2] = 33;
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
执行过程:
- .class文件加载到方法区,main方法进入栈。
- 执行int[] arr = new int[3],在堆中开辟数组空间(地址0x001),长度为3,默认值0。
- 地址赋给栈中的arr变量。
- 通过索引赋值,修改堆中对应元素的值。
- 打印时,arr通过地址找到堆中数组,再按索引取出元素。
两个数组内存图
int[] arr1 = new int[2];
arr1[0] = 11;
arr1[1] = 22;
int[] arr2 = new int[3];
arr2[0] = 33;
arr2[1] = 44;
arr2[2] = 55;
关键点:每次new都会在堆中开辟一块新的空间,地址不会重复。
多个数组指向相同内存
int[] arr1 = new int[2];
arr1[0] = 11;
arr1[1] = 22;
int[] arr2 = arr1; // 将arr1记录的地址赋给arr2
arr2[0] = 33;
System.out.println(arr1[0]); // 33
System.out.println(arr1[1]); // 22
System.out.println(arr2[0]); // 33
System.out.println(arr2[1]); // 22
当两个引用指向同一个数组时,通过任何一个引用修改数组,另一个引用看到的也是修改后的结果。可以把引用想象成“遥控器”,多个遥控器控制同一台电视。
数组静态初始化
静态初始化:在创建数组时直接指定元素的值,系统自动计算长度
完整格式
数据类型[] 数组名 = new 数据类型[]{元素1, 元素2, ...};
简化格式
数据类型[] 数组名 = {元素1, 元素2, ...};
示例:
int[] arr = new int[]{11, 22, 33};
int[] arr2 = {44, 55, 66};
简化格式虽然没有显式写new,但编译器会补齐,实际仍然会在堆中开辟空间。
动态初始化 vs 静态初始化
| 动态初始化 | 静态初始化 | |
|---|---|---|
| 指定 | 数组长度 | 元素的具体值 |
| 系统计算 | 默认值 | 数组长度 |
| 适用场景 | 只明确元素个数,不明确具体值(如键盘录入) | 已经明确要操作的具体数据 |
数组操作常见问题
1 )索引越界
访问了不存在的索引,抛出 ArrayIndexOutOfBoundsException
int[] arr = new int[3]; // 索引0~2
System.out.println(arr[3]); // 越界
避免方法:访问索引前确保 0 <= 索引 < 数组长度,通常用arr.length控制循环。
2 )空指针异常
数组变量不再指向任何堆内存空间(记录null),仍试图访问元素,抛出NullPointerException
int[] arr = new int[3];
arr = null;
System.out.println(arr[0]); // 空指针异常
null是引用类型的默认值,表示“空”,不指向任何对象
数组遍历
1 ) 遍历:逐一获取数组中的每个元素。常用for循环配合数组名.length
int[] arr = {11, 22, 33, 44, 55};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
2 ) 改进:一行打印数组元素
需求:将数组元素按格式 [11, 22, 33, 44, 55] 在一行打印。
public static void printArray(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i] + "]");
} else {
System.out.print(arr[i] + ", ");
}
}
// 换行
System.out.println();
}
数组获取最大值
1 ) 思路:
- 假设第一个元素为最大值
max = arr[0] - 遍历剩余元素,如果发现更大的值,则更新max
- 遍历结束,max即为最大值
int[] arr = {12, 45, 98, 73, 60};
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
System.out.println("max:" + max);
最小值同理,只需将比较条件改为 arr[i] < min
数组元素求和
需求:键盘录入5个整数,存入数组并求和。典型动态初始化场景。
Scanner sc = new Scanner(System.in);
int sum = 0;
int[] arr = new int[5];
for (int i = 0; i < arr.length; i++) {
System.out.println("请输入第" + (i + 1) + "个整数:");
arr[i] = sc.nextInt();
}
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
System.out.println("sum:" + sum);
数组基本查找
需求:已知数组,键盘录入一个数据,查找其在数组中的索引,找不到返回-1。
int[] arr = {19, 28, 37, 46, 50};
Scanner sc = new Scanner(System.in);
System.out.println("请输入您要查找的元素:");
int num = sc.nextInt();
int index = -1; // 假设不存在
for (int i = 0; i < arr.length; i++) {
if (arr[i] == num) {
index = i;
break; // 找到后结束循环
}
}
System.out.println(index);
评委打分案例
需求:6个评委打分(0~100),去掉一个最高分和一个最低分,求平均分(不考虑小数)。
int[] arr = new int[6];
Scanner sc = new Scanner(System.in);
// 录入评委分数,并保证数据合法
for (int i = 0; i < arr.length; i++) {
System.out.println("请输入第" + (i + 1) + "个评委的打分:");
int score = sc.nextInt();
if (score >= 0 && score <= 100) {
arr[i] = score;
} else {
System.out.println("您的打分输入有误, 请检查是否是0-100之间的");
i--; // 重新输入本位置
}
}
// 求最大值
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) max = arr[i];
}
// 求最小值
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] < min) min = arr[i];
}
// 求和
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
// 计算平均分
int avg = (sum - max - min) / 4;
System.out.println(avg);
i--的作用:当输入非法分数时,强迫用户重新输入当前评委的分数,保证数组最终只存储合法值。
总结
本文从数组的概念、定义、初始化到内存模型、常见操作和经典案例,全面介绍了Java数组的基础知识。
掌握数组是学习Java集合等高级特性的重要前提,建议多动手练习,理解内存分配与引用机制。

2万+

被折叠的 条评论
为什么被折叠?



