欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > Java数组详解/从JVM理解数组/数组反转/随机排名/数组在计算机如何存储

Java数组详解/从JVM理解数组/数组反转/随机排名/数组在计算机如何存储

2025/6/28 0:33:48 来源:https://blog.csdn.net/weixin_59786087/article/details/146059272  浏览:    关键词:Java数组详解/从JVM理解数组/数组反转/随机排名/数组在计算机如何存储

本文详细讲解了数组的定义、数组的访问方法、数组的遍历、静态数组和动态数组、以及数组中的自动类型转换、引用类型指向数组的地址、以及从JVM理解数组、空指针异常、数组反转、随机排名的案例。

数组是存放在连续内存空间上的相同类型数据的集合。

数组可以方便的通过下标索引的方式获取到下标对应的数据。

举一个字符数组的例子,如图所示:

需要两点注意的是

  • 数组下标都是从0开始的。

  • 数组内存空间的地址是连续的

正是因为数组在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。


一、数组的定义和访问

1.静态初始化数组

  • 定义数组的时候直接给数组赋值。

完整模式:
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3};
int[] a = new int[]{1,2,3,4,5};
​
简化格式:
数据类型[] 数组名 = {元素1,元素2,元素3};
double[] score = {85.5,75.5,90.5};
​
其他写法:
左边:数据类型[] 数组名 也可以写成 数据类型 数组名[]
源码中可能会看到这种写法。
​

[重点]数组中的自动类型转换

虽然,数组只能保存相同数据类型的数据。

但,如果存储字符类型,编译的时候也不会报错

  • 我们知道byte、short、char能自动类型转换为int

  • float能自动类型转换为double类型。

数组中也可以:

int[] numbers = {10, (byte)20, (short)30, 'A'}; 
// 等价于 {10, 20, 30, 65},自动转换为int
double[] decimals = {1, 2.5f, 3L}; 
// 等价于 {1.0, 2.5, 3.0},自动转换为double

System.out.println(Arrays.toString(ages1)); // 输出 [12, 24, 36, 65]

二、数组在计算机中的基本原理

数组是引用数据类型,存储数组在内存中的地址信息。

int[] args = new int[]{1,2,3,4};

[重点]这里args是一个数组的对象,数组是引用数据类型,存储数组在内存中的地址信息。

[重点]数组地址分析

  • 那么我们打印这个数组会发生什么?

打印出数组(引用数据类型)的地址。

[I@776ec8df]

//@ 占位符,读法at

//[ 数组

//I int

//776ec8df 内存地址

详情见:Java中的对象存储形式及控制台输出哈希码问题

回顾:

1.数组的静态初始化的写法和特点是什么?

我们再默写一遍
数据类型[] 数组名 = new 数据类型[]{1,2,3};
​
数据类型[] 数组名 = {1,2,3,4};
​

如上,能够简写,或者源码写法。

数据类型 数组名[] = {1,2,3,4};

2.定义数组我们说了那几个注意点?

1.什么类型的数组就存放什么样的数据。也有特例,不过能编译。一般,数组只能存储一种数据类型的数据

2.可以源码写法

3.数组属于什么类型?数组变量名中存储的是什么?

数组属于引用数据类型,存储的是数组在内存中的地址信息


三、数组的访问

数组名称[索引]

数组的长度

数组名.length

[重点]末尾元素:数组名.length - 1的前提条件

ArrayIndexOutOfBoundsException

前提数组中的元素>0

回顾:

1.如何访问数组元素?

数字名[索引]

2.如何访问数组长度?

数组名.length

3.数组的最大索引/数组末尾元素是多少?

数组名.length -1

4.如果访问数组的时候,使用索引超过数组的最大索引会出现什么问题?

ArrayIndexOutOfBoundsException数组索引越界异常。

四、数组遍历

为什么,因为要进行数组元素的比较。

快捷键:args.fori,选择fori能自动快速生成遍历数组

案例-求和

package com.itheima.array.define;
​
public class ArrayTest4 {public static void main(String[] args) {
//        某员工的销售额是16,26,36,6,100,请计算他们部门的总销售额。int[] arg = {16,26,36,6,100};
//        求和思想:/*1.定义变量* 2.进行累加* */int sum = 0;for (int i = 0; i < arg.length; i++) {sum += arg[i];}System.out.println(sum);
​}
}
​

2.动态数组初始化

其实是没有规定元素是什么,而是规定元素的数据类型和个数

数据类型[] 数组名 = mew 数据类型[元素个数];
int args = new int[3];

args[0] =10;//后赋值

我们知道,对象都存在于堆内存中,这里动态数组也是,存在堆内存中,直接打印数组,会出现在堆内存中的地址(哈希码形式)。

注意:

不要混了

[重点]动态初始化数组元素默认值规则:
分类数据类型默认值
基本类型byte, short, char(Unicode是\u0000)显示空白字符, int, long0
浮点型float, double0.0
布尔型booleanfalse
引用数据类型, 接口, 数组, Stringnull

其实String也是对象

注意boolean类型是false。

[重点]注意char数组的默认值为\u0000(Unicode空字符)对应的ASCII码值为0。控制台输出不是0

但直接打印时,\u0000不会显示为字符0,而是显示为“空白”(不可见字符)。

而是这个符号,代表Unicopde中的\u0000,不可见符号。

重点
package com.itheima.array.define;
​
public class ArrayDemo5 {public static void main(String[] args) {//注意char是Unicode编码(\u0000)char []arr = new char[3];System.out.println(arr[0]);System.out.println("===");
​int []arr1 = new int[3];System.out.println(arr1[0]);System.out.println("===");
​byte[]arr3 = new byte[3];System.out.println(arr3[0]);System.out.println("===");
​short[]arr2 = new short[3];System.out.println(arr2[0]);System.out.println("===");
​
​long[] arr31 = new long[3];System.out.println(arr31[0]);System.out.println("===");
​float[] arr4 = new float[3];System.out.println(arr4[0]);System.out.println("===");
​double[] arr5 = new double[3];System.out.println(arr5[0]);System.out.println("===");
​String[] arr6 = new String[3];System.out.println(arr6[0]);System.out.println("===");}
}
​

回顾:

1.动态初始化数组的写法是什么?

数据类型[] 数组名 = new 数据类型[长度];
int [] args = new int[5]

2.动态初始化数组的默认值是什么?

byte、short、int、char、long是0

float、double是0.0

boolean是false

String、类、接口、数组等引用数据类型是null。

3.两种数组定义的方法各自适用于什么业务场景?

静态初始化数组:适用于确定是数组元素的场景;

动态初始化:适用于只确定数组元素个数的场景


案例-求评委打分平均分

package com.itheima.array.define;
​
import java.sql.SQLOutput;
import java.util.Scanner;
​
public class ArrayTest5 {public static void main(String[] args) {//需求:现在有6个评委,给1名选手进行打分。请你求该选手的平均分
​//首先,数组存储//先解决单次一个人录入,然后存入数组//之后累加求和//最后求平均分sum/数组长度
​//完成单次录入/*    int[] arr = new int[6];Scanner sc = new Scanner(System.in);arr[0]= sc.nextInt();System.out.println("第一个评委的打分是"+ arr[0]);*/
​int[] arr = new int[6];//改为多次录入ctrl+alt+tfor (int i = 0; i < arr.length; i++) {//0-5索引
//            System.out.println("请输入" + (i + 1) + "个评委的打分");
​Scanner sc = new Scanner(System.in);arr[i] = sc.nextInt();System.out.println("第" + (i + 1) + "个评委的打分是" + arr[i]);}
//        得到六个评委打分并存入数组//累加求和int sum = 0;//快捷键 arr.forifor (int i = 0; i < arr.length; i++) {
​sum += arr[i];}System.out.println("评委总分" + sum);
​//求平均分int avg = sum / arr.length;System.out.println("评委打分的平均分是" + avg);}
}
​

数组在计算机中的执行原理

JVM的内存划分

  • 方法区

  • 本地方法栈

  • 寄存器

方法区:加载字节码.class文件

栈内存:方法执行的时候进栈,方法中的变量存储也在栈内存。

堆内存:new出来的东西会在这块内存中开辟空间并产生地址。

讲解:

栈内存给main方法分配区域(栈帧)那么a就在栈内存中划分了一块区域,

执行打印,这里根据a找到区域,然后打印执行。

数组创建,那么就在堆内存中创建数组对象,数组对象也有地址,这个地址也会存到栈内存中。

通过arr存在栈内存的这个地址,找这个数组对象。

  • 其实arr是引用变量,是存在栈内存中的。

数组赋值之后真正产生变化的是堆内存的数据,而不栈中,栈中只有地址,

最后打印。

回顾:

方法区:执行class文件

执行方法,进入栈内存

new对象进入堆内存,

2.简单说说inta=20;int[]arr=new int[3]这两行代码的执行原理?

a是变量,直接放在栈内存中,a变量中存储的数据就是20这个值。

new int[3]是创建一个数组对象,会在堆内存中开辟区域存储3个整数。


[重点]案例:多个变量指向同一个数组

引用变量:引用数据类型的变量

1.多个变量指向同一个数组

引用变量arr1和arr2都是指向堆内存中同一个区域,那么其实赋值给arr2[1]==99;后修改的是堆内存中存储的数据。

2.赋值null

详见代码

package com.itheima.memory;
​
public class Demo1 {public static void main(String[] args) {//目标:多个变量指向同一个数组对象的执行原理//这个变量指的是引用变量,引用变量,就是引用数据类型的变量。数组就是引用数据类型
​//创建两个数组int arr1[] = {1,2,3};int arr2[] = arr1;//我们将arr1赋值给arr2,实际上是让 存在栈内存中的引用变量 指向 同一堆内存中的对象,也就是数组的元素。System.out.println(arr1);System.out.println(arr2);System.out.println("可以看到,两个数组的引用变量的地址是一致的,指向的是同一个堆内存中的区域");//如果我们修改arr2的一个元素,那arr1会改变吗?arr2[0] = 99;System.out.println(arr1[0]);//arr1也改变了System.out.println(arr1);System.out.println(arr2);////以上,证明了arr1和arr2两个引用数据类型的变量,指向的是堆内存中的同一块区域,而且修改后同时发生改变。
​System.out.println("============【重点】如果赋值null===============");//2.如果赋值nullarr2 = null;
//        System.out.println(arr2.length);System.out.println(arr1.length);System.out.println("编译不报错,因为arr2数组有length方法,输出arr2.length会运行报错");System.out.println("但是输出arr1.length不会报错,因为实际上修改的是引用变量arr2,arr1指向堆内存中的对象没有发生变化");}
​
}
​

执行过程图解:

[重点]空指针异常代表:引用数据类型的变量,该有东西,但是为空

[重点]回顾:

1.多个数组变量,指向同一个数组对象的原因是什么?需要注意什么?

因为创建数组的时候,这两个引用数据类型变量,指向的都是同一个数组对象。存储的都是同一个数组对象的地址。

注意:多变量修改的都是同一个数组对象的数据

2.如果某个数组变量中存储的null,代表什么意思?需要注意什么?

代表这个数组变量(引用类型变量),没有指向同一个对象。

可以输出这个变量,但是访问数组元素或获取数组长度,报NullPointerException

代码如下:

package com.itheima.memory;
​
public class Demo2 {//2.如果某个数组变量中存储的null,代表什么意思?需要注意什么?public static void main(String[] args) {
​int arr[] = new int[]{1,2};//引用变量赋值为nullarr = null;System.out.println(arr);//可以打印出null
​int length1= arr.length;//访问数组长度:NullPointerExceptionSystem.out.println(length1);
​int num = arr[0];//获取数组元素:NullPointerExceptionSystem.out.println(num);
​}
​
}
 

代码如下:

package com.itheima.memory;
​
public class Demo1 {public static void main(String[] args) {//目标:多个变量指向同一个数组对象的执行原理//1.修改元素//这个变量指的是引用变量,引用变量,就是引用数据类型的变量。数组就是引用数据类型
​//创建两个数组int arr1[] = {1,2,3};int arr2[] = arr1;//我们将arr1赋值给arr2,实际上是让 存在栈内存中的引用变量 指向 同一堆内存中的对象,也就是数组的元素。System.out.println(arr1);System.out.println(arr2);System.out.println("可以看到,两个数组的引用变量的地址是一致的,指向的是同一个堆内存中的区域");//如果我们修改arr2的一个元素,那arr1会改变吗?arr2[0] = 99;System.out.println(arr1[0]);//arr1也改变了System.out.println(arr1);System.out.println(arr2);////以上,证明了arr1和arr2两个引用数据类型的变量,指向的是堆内存中的同一块区域,而且修改后同时发生改变。
​System.out.println("============【重点】如果赋值null===============");//2.如果赋值nullarr2 = null;
//        System.out.println(arr2.length);System.out.println(arr1.length);System.out.println("编译不报错,因为arr2数组有length方法,输出arr2.length会运行报错");System.out.println("但是输出arr1.length不会报错,因为实际上修改的是引用变量arr2,arr1指向堆内存中的对象没有发生变化");}
​
}
​

编译不报错,因为arr2数组有length方法,输出arr2.length会运行报错

但是输出arr1.length不会报错,因为实际上修改的是引用变量arr2,arr1指向堆内存

的对象没有发生变化。

[重点]案例,求数组元素中的最大值,最小值

要点:确定固定值max。以及。从第二个位置开始遍历元素。

1.首先用MAX变量作为数组中的一个元素,默认arr[0]。(就是一个普通的固定值,默认为0都可以)

2.从第二个位置开始遍历数组的元素,比较后,赋值到MAX变量中。因为是循环语句套在外面,跳出不了循环,那么会一直比较,所有的元素。大的就再次赋值,小的就继续循环。会直到循环结束。


package com.itheima.array;
​
public class ArrayTest3 {public static void main(String[] args) {//数组,求最大值int arr[] = {1,2,3,4,5,5,6,7,8,10,6};
​int max = arr[0];//仅仅是一个固定值而已,赋值为数组中的一个元素,这样普遍性更强,否则如果是0,0可能是数组元素中最大或最小的。//arr.length-1 是指数组最后一个元素for (int i = 0; i < arr.length; i++) {if(max < arr[i]){max = arr[i];}}System.out.println(max);}
}
​

[重点]数组反转

int temp1 = arr1[0];//仅仅是一个固定值,这里赋值0也可以。表示成这样,方便阅读。

package com.itheima.array.cases;
​
public class Test2 {public static void main(String[] args) {//1.变量互换int a = 250;int b = 985;int temp = 0;
​temp = a;a = b;b = temp;System.out.println("a:" + a + "\n" + "b:" + b);System.out.println("======2.数组元素互换==============");//2.数组元素互换//让第一个和倒数第一个互换,第二个和倒数第二个互换,第三个和倒数第三个互换...int arr1[] = new int[]{10, 20, 30, 40, 50};int temp1 = arr1[0];//仅仅是一个固定值,这里赋值0也可以。表示成这样,方便阅读for (int i = 0, j = (arr1.length - 1); i < j; i++, j--) {//当i不小于j的时候进行结束,也就是刚好等于的时候//相当于变量互换temp1 = arr1[j];arr1[i] = arr1[j];arr1[i] = temp1;}//输出for (int i = 0; i < arr1.length; i++) {System.out.print(arr1[i] + "\t");}}
}
​

[难点]随机排名

package com.itheima.array.cases;
​
import java.util.Random;
import java.util.Scanner;
​
public class ArrayRandomRange_import_3 {public static void main(String[] args) {//非常熟练
//需求:现在有五名创业者需要进行路演,他们分别有工号,但是为确保公平性,现在想随机上台路演。请你实现功能int c_num[] = new int[5];Scanner sc = new Scanner(System.in);
​//输入5个工号for (int i = 0; i < c_num.length; i++) {System.out.println("请你输入第"+(i+1)+"个工号");int num = sc.nextInt();c_num[i] = num;}
​//随机工号for (int j = 0; j < c_num.length; j++) {Random r = new Random();int ranDomIndex = r.nextInt(c_num.length);//nextInt()产生的是[0,4]与数组对应,不用[加减法]。//交换:(以随机索引的数组)=>数组的随机的另一个元素  与 本数组元素 按照迭代顺序交换。[首位呼应一条龙]//实际是:该数组的元素相互进行交换。//只是ranDomIndex是独立事件,会有重复数,会重复交换,导致随机的不是很彻底。int temp = 0;temp = c_num[j];c_num[j] = c_num[ranDomIndex];//先写,现在看就是数组俩元素进行交换,只是这个地方改成了ranDdonIndexc_num[ranDomIndex] = temp;}//输出for (int k = 0; k < c_num.length; k++) {System.out.print(c_num[k] +" ");       }}
}
​

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词