一、数组原理内存图
1、内存概述
内存是计算机中的重要原件,临时存储区域,作用是运行程序,我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放在内存中才能运行,运行完毕后会清空内存。
Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。
2、Java虚拟机的内存划分
为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
- JVM的内存划分
| 区域名称 | 作用 |
|---|---|
| 寄存器 | 给CPU使用,和开发无关 |
| 本体方法栈 | JVM在使用操作系统功能的时候使用,和我们开发无关 |
| 方法区 | 存储可以运行的.class 文件 |
| 堆内存 | 存储对象或数组,new来创建的,都存储在堆内存 |
| 方法栈 | 方法运行时使用的内存,比如main方法运行,进入方法栈中执行 |
3、数组在内存中的存储
(1)、一个数组内存图
public static void main(String[] args){
int[] arr = new int[3];
System.out.println(arr); //[I@7c30a502
}
以上方法执行,输出的结果是[I@7c30a502,这个是什么?是数组在内存中的地址,new出来的内容,都在堆内存中存储,二方法中的arr保存的是数组的地址。
输出arr[0],就会输出arr保存的内存地址中数组索引为0的元素。
程序执行流程:
- 1、
main方法进入方法栈执行 - 2、创建数组,JVM会在堆内存中开辟空间,存储数组
- 3、数组在内存中会有自己的内存地址,以十六进制数表示
- 4、数组中有3个元素,默认值为0
- 5、JVM将数组的内存地址赋值给引用类型变量
arr - 6、变量
arr保存的是数组内存中的地址,而不是一个具体数值,因此称为引用数据类型

(2)、两个数组内存图
public static void main(String[] args){
int[] arr1 = new int[3];
int[] arr2 = new int[2];
System.out.println(arr1);
System.out.println(arr2);
}

(3)、两个变量指向一个数组
public static void main(String[] args){
// 定义数组。存储3个元素
int[] arr = new int[3];
// 数组索引进行赋值
arr[0] = 5;
arr[1] = 6;
arr[2] = 7;
// 输出元素值
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
// 定义数组变量arr2,将arr的地址赋值arr2
int[] arr2 = arr;
arr2[1] = 9;
System.out.println(arr[1]);
}

(4)、举例

二、数组的常见操作
1、数组越界异常
看下面代码:
public static void main(String[] args){
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
}
创建数组,赋值3个元素,数组的索引就是0, 1, 2,没有索引3,因此我们不能访问数组中不存在的索引,程序运行后,将会抛出ArrayIndexOutOfBoundsException数组越界异常。在开发中,数组的越界异常是不能出现的,一旦出现,就需要修改代码。
2、数组空指针异常
观察以下代码,运行后会出现什么结果。
public static void main(String[] args){
int[] arr = {1, 2, 3};
arr = null;
System.out.println(arr[0]);
}
arr = null这行代码,意味着变量arr将不会保存数组的内存地址,也就不允许再操作数组了,因此运行的时候会抛出NullPointerException空指针异常。在开发中,数组的越界异常是不能出现的,一旦出现,就必须修改代码。
空指针在内存图中的表现

3、数组遍历【重点】
- 数组遍历:就是将数组中的每个元素都分别获取出来,就是遍历。遍历也是数组操作中的基石。
public static void main(String[] args){
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8};
arr.length.
}
4、数组获取最大值元素
- 最大值获取:从数组的所有元素中找出最大值
- 实现思路:
- 定义变量,保存数组索引0的元素A
- 遍历数组,获取出数组中的每个元素
- 将遍历到的元素和保存数组A进行比较
- 如果数组元素A的值大于遍历的元素值,就将A记为最大值,否则将遍历的值记为最大值
- 数组循环遍历结束,得到最大值
public static void main(String[] args) {
int[] arr = {5, 15, 30, 20, 1000};
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i] > max){
max = arr[i];
}
}
System.out.println(max);
}
5、数组反转
- 数组反转:数组中的元素颠倒顺序
- 实现思路:数组最远端的元素互换位置(要求原地反转)
public static void arrayReverseReplace(int[] arr){
int i = 0;
int j = arr.length - 1;
int temp;
while(i < j){
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
}
三、数组作为方法参数和返回值
1、数组作为方法参数
以前的方法中学习了方法的参数和返回值,但是使用的都是基本数据类型,那么作为引用类型的数组能够作为方法的参数进行传递呢?当然可以!
- 数组作为方法参数传递,传递的参数都是数组内存的地址
public static void main(String[] args){
int[] arr = {1, 3, 5, 7, 9};
//调用方法,传递数组
printArray(arr);
}
public static void printArray(int[] arr){
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
}
2、数组作为方法返回值
- 数组作为方法的返回值,返回的是数组的内存地址
- 一个方法可以有0、1、或多个参数,但是只能有0或1个返回值,不能有多个返回值, 如果希望一个方法当中产生多个结果的返回值,可以使用一个数组作为返回值类型即可
public static void main(String[] args){
//调用方法,接收数组的返回值
//接受到的是数组的内存地址
int[] arr = getArray();
for (int i = 0; i < arr.length, i++){
System.out.println(arr[i]);
}
}
public static int[] getArray(){
int[] arr = {1, 3, 4, 5, 6};
return arr;
}
public static void main(String[] args) {
int[] result = calculate(10, 20);
System.out.println("总和为:" + result[0]);
System.out.println("平均数:" + result[1]);
}
public static int[] calculate(int a, int b){
int sum = a + b;
int avg = sum / 3;
int[] res = {sum, avg};
return res;
}
总结:方法的参数为基本类型时,传递的是数据值,方法的参数为引用类型时,传递的是地址值.