Java数组详解/从JVM明白数组/数组反转/随机排名/数组在盘算机如何存储 ...

打印 上一主题 下一主题

主题 976|帖子 976|积分 2928

本文具体讲解了数组的界说、数组的访问方法、数组的遍历、静态数组和动态数组、以及数组中的自动范例转换、引用范例指向数组的地点、以及从JVM明白数组、空指针异常、数组反转、随机排名的案例。

数组是存放在连续内存空间上的类似范例数据的聚集。

数组可以方便的通过下标索引的方式获取到下标对应的数据。
举一个字符数组的例子,如图所示:

必要两点留意的是


  • 数组下标都是从0开始的。
  • 数组内存空间的地点是连续的
正是因为数组在内存空间的地点是连续的,以是我们在删除或者增添元素的时候,就难免要移动其他元素的地点。



一、数组的界说和访问

1.静态初始化数组



  • 界说数组的时候直接给数组赋值。
  1. 完整模式:
  2. 数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3};
  3. int[] a = new int[]{1,2,3,4,5};
  4. 简化格式:
  5. 数据类型[] 数组名 = {元素1,元素2,元素3};
  6. double[] score = {85.5,75.5,90.5};
  7. 其他写法:
  8. 左边:数据类型[] 数组名 也可以写成 数据类型 数组名[]
  9. 源码中可能会看到这种写法。
复制代码

[重点]数组中的自动范例转换

虽然,数组只能生存类似数据范例的数据。
但,假如存储字符范例,编译的时候也不会报错


  • 我们知道byte、short、char能自动范例转换为int
  • float能自动范例转换为double范例。
数组中也可以:
  1. int[] numbers = {10, (byte)20, (short)30, 'A'};
  2. // 等价于 {10, 20, 30, 65},自动转换为int
  3. double[] decimals = {1, 2.5f, 3L};
  4. // 等价于 {1.0, 2.5, 3.0},自动转换为double
复制代码


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

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

数组是引用数据范例,存储数组在内存中的地点信息。
  1. int[] args = new int[]{1,2,3,4};
复制代码
[重点]这里args是一个数组的对象,数组是引用数据范例,存储数组在内存中的地点信息。


[重点]数组地点分析



  • 那么我们打印这个数组会发生什么?
打印出数组(引用数据范例)的地点。

[I@776ec8df]
//@ 占位符,读法at
//[ 数组
//I int
//776ec8df 内存地点

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

回顾:

1.数组的静态初始化的写法和特点是什么?
  1. 我们再默写一遍
  2. 数据类型[] 数组名 = new 数据类型[]{1,2,3};
  3. 数据类型[] 数组名 = {1,2,3,4};
复制代码
如上,可以或许简写,或者源码写法。
  1. 数据类型 数组名[] = {1,2,3,4};
复制代码

2.界说数组我们说了那几个留意点?
1.什么范例的数组就存放什么样的数据。也有特例,不过能编译。一样平常,数组只能存储一种数据范例的数据
2.可以源码写法


3.数组属于什么范例?数组变量名中存储的是什么?
数组属于引用数据范例,存储的是数组在内存中的地点信息


三、数组的访问

数组名称[索引]
数组的长度

数组名.length

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


  1. ArrayIndexOutOfBoundsException
复制代码
前提数组中的元素>0

回顾:

1.如何访问数组元素?
数字名[索引]
2.如何访问数组长度?
数组名.length
3.数组的最大索引/数组末尾元素是多少?
数组名.length -1
4.假如访问数组的时候,使用索引超过数组的最大索引会出现什么问题?
ArrayIndexOutOfBoundsException数组索引越界异常。

四、数组遍历

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

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

案例-求和

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

2.动态数组初始化

其实是没有规定元素是什么,而是规定元素的数据范例和个数
  1. 数据类型[] 数组名 = mew 数据类型[元素个数];
  2. int args = new int[3];
复制代码
args[0] =10;//后赋值
我们知道,对象都存在于堆内存中,这里动态数组也是,存在堆内存中,直接打印数组,会出如今堆内存中的地点(哈希码形式)。

留意:
不要混了


[重点]动态初始化数组元素默认值规则:

分类数据范例默认值基本范例byte, short, char(Unicode是\u0000)显示空白字符, int, long0浮点型float, double0.0布尔型booleanfalse引用数据范例类, 接口, 数组, String等null 其实String也是对象
留意boolean范例是false。
[重点]留意char数组的默认值为\u0000(Unicode空字符)对应的ASCII码值为0。控制台输出不是0

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

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

重点

  1. package com.itheima.array.define;
  2. public class ArrayDemo5 {
  3.    public static void main(String[] args) {
  4.        //注意char是Unicode编码(\u0000)
  5.        char []arr = new char[3];
  6.        System.out.println(arr[0]);
  7.        System.out.println("===");
  8.        int []arr1 = new int[3];
  9.        System.out.println(arr1[0]);
  10.        System.out.println("===");
  11.        byte[]arr3 = new byte[3];
  12.        System.out.println(arr3[0]);
  13.        System.out.println("===");
  14.        short[]arr2 = new short[3];
  15.        System.out.println(arr2[0]);
  16.        System.out.println("===");
  17.        long[] arr31 = new long[3];
  18.        System.out.println(arr31[0]);
  19.        System.out.println("===");
  20.        float[] arr4 = new float[3];
  21.        System.out.println(arr4[0]);
  22.        System.out.println("===");
  23.        double[] arr5 = new double[3];
  24.        System.out.println(arr5[0]);
  25.        System.out.println("===");
  26.        String[] arr6 = new String[3];
  27.        System.out.println(arr6[0]);
  28.        System.out.println("===");
  29.    }
  30. }
复制代码


回顾:

1.动态初始化数组的写法是什么?
  1. 数据类型[] 数组名 = new 数据类型[长度];
  2. int [] args = new int[5]
复制代码

2.动态初始化数组的默认值是什么?
byte、short、int、char、long是0
float、double是0.0
boolean是false
String、类、接口、数组等引用数据范例是null。
3.两种数组界说的方法各自适用于什么业务场景?
静态初始化数组:适用于确定是数组元素的场景;
动态初始化:适用于只确定命组元素个数的场景



案例-求评委打分平均分

  1. package com.itheima.array.define;
  2. import java.sql.SQLOutput;
  3. import java.util.Scanner;
  4. public class ArrayTest5 {
  5.    public static void main(String[] args) {
  6.        //需求:现在有6个评委,给1名选手进行打分。请你求该选手的平均分
  7.        //首先,数组存储
  8.        //先解决单次一个人录入,然后存入数组
  9.        //之后累加求和
  10.        //最后求平均分sum/数组长度
  11.        //完成单次录入
  12.    /*    int[] arr = new int[6];
  13.        Scanner sc = new Scanner(System.in);
  14.        arr[0]= sc.nextInt();
  15.        System.out.println("第一个评委的打分是"+ arr[0]);*/
  16.        int[] arr = new int[6];
  17.        //改为多次录入ctrl+alt+t
  18.        for (int i = 0; i < arr.length; i++) {//0-5索引
  19. //            System.out.println("请输入" + (i + 1) + "个评委的打分");
  20.            Scanner sc = new Scanner(System.in);
  21.            arr[i] = sc.nextInt();
  22.            System.out.println("第" + (i + 1) + "个评委的打分是" + arr[i]);
  23.        }
  24. //        得到六个评委打分并存入数组
  25.        //累加求和
  26.        int sum = 0;
  27.        //快捷键 arr.fori
  28.        for (int i = 0; i < arr.length; i++) {
  29.            sum += arr[i];
  30.        }
  31.        System.out.println("评委总分" + sum);
  32.        //求平均分
  33.        int avg = sum / arr.length;
  34.        System.out.println("评委打分的平均分是" + avg);
  35.    }
  36. }
复制代码


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

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
详见代码
  1. package com.itheima.memory;
  2. public class Demo1 {
  3.    public static void main(String[] args) {
  4.        //目标:多个变量指向同一个数组对象的执行原理
  5.        //这个变量指的是引用变量,引用变量,就是引用数据类型的变量。数组就是引用数据类型
  6.            //创建两个数组
  7.        int arr1[] = {1,2,3};
  8.        int arr2[] = arr1;//我们将arr1赋值给arr2,实际上是让 存在栈内存中的引用变量 指向 同一堆内存中的对象,也就是数组的元素。
  9.        System.out.println(arr1);
  10.        System.out.println(arr2);
  11.        System.out.println("可以看到,两个数组的引用变量的地址是一致的,指向的是同一个堆内存中的区域");
  12.            //如果我们修改arr2的一个元素,那arr1会改变吗?
  13.        arr2[0] = 99;
  14.        System.out.println(arr1[0]);//arr1也改变了
  15.        System.out.println(arr1);
  16.        System.out.println(arr2);//
  17.        //以上,证明了arr1和arr2两个引用数据类型的变量,指向的是堆内存中的同一块区域,而且修改后同时发生改变。
  18.        System.out.println("============【重点】如果赋值null===============");
  19.        //2.如果赋值null
  20.        arr2 = null;
  21. //        System.out.println(arr2.length);
  22.        System.out.println(arr1.length);
  23.        System.out.println("编译不报错,因为arr2数组有length方法,输出arr2.length会运行报错");
  24.        System.out.println("但是输出arr1.length不会报错,因为实际上修改的是引用变量arr2,arr1指向堆内存中的对象没有发生变化");
  25.    }
  26. }
复制代码


执行过程图解:




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



[重点]回顾:

1.多个数组变量,指向同一个数组对象的缘故原由是什么?必要留意什么?
因为创建数组的时候,这两个引用数据范例变量,指向的都是同一个数组对象。存储的都是同一个数组对象的地点。
留意:多变量修改的都是同一个数组对象的数据

2.假如某个数组变量中存储的null,代表什么意思?必要留意什么?
代表这个数组变量(引用范例变量),没有指向同一个对象。
可以输出这个变量,但是访问数组元素或获取数组长度,报NullPointerException
代码如下:
  1. package com.itheima.memory;
  2. public class Demo2 {
  3.    //2.如果某个数组变量中存储的null,代表什么意思?需要注意什么?
  4.    public static void main(String[] args) {
  5.        int arr[] = new int[]{1,2};
  6.    //引用变量赋值为null
  7.        arr = null;
  8.        System.out.println(arr);//可以打印出null
  9.        int length1= arr.length;//访问数组长度:NullPointerException
  10.        System.out.println(length1);
  11.        int num = arr[0];//获取数组元素:NullPointerException
  12.        System.out.println(num);
  13.    }
  14. }
复制代码
  1. [/code]
  2. 代码如下:
  3. [code]package com.itheima.memory;
  4. public class Demo1 {
  5.    public static void main(String[] args) {
  6.        //目标:多个变量指向同一个数组对象的执行原理
  7.        //1.修改元素
  8.        //这个变量指的是引用变量,引用变量,就是引用数据类型的变量。数组就是引用数据类型
  9.            //创建两个数组
  10.        int arr1[] = {1,2,3};
  11.        int arr2[] = arr1;//我们将arr1赋值给arr2,实际上是让 存在栈内存中的引用变量 指向 同一堆内存中的对象,也就是数组的元素。
  12.        System.out.println(arr1);
  13.        System.out.println(arr2);
  14.        System.out.println("可以看到,两个数组的引用变量的地址是一致的,指向的是同一个堆内存中的区域");
  15.            //如果我们修改arr2的一个元素,那arr1会改变吗?
  16.        arr2[0] = 99;
  17.        System.out.println(arr1[0]);//arr1也改变了
  18.        System.out.println(arr1);
  19.        System.out.println(arr2);//
  20.        //以上,证明了arr1和arr2两个引用数据类型的变量,指向的是堆内存中的同一块区域,而且修改后同时发生改变。
  21.        System.out.println("============【重点】如果赋值null===============");
  22.        //2.如果赋值null
  23.        arr2 = null;
  24. //        System.out.println(arr2.length);
  25.        System.out.println(arr1.length);
  26.        System.out.println("编译不报错,因为arr2数组有length方法,输出arr2.length会运行报错");
  27.        System.out.println("但是输出arr1.length不会报错,因为实际上修改的是引用变量arr2,arr1指向堆内存中的对象没有发生变化");
  28.    }
  29. }
复制代码

编译不报错,因为arr2数组有length方法,输出arr2.length会运行报错
但是输出arr1.length不会报错,因为实际上修改的是引用变量arr2,arr1指向堆内存
的对象没有发生变革。



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

要点:确定固定值max。以及。从第二个位置开始遍历元素。
1.起首用MAX变量作为数组中的一个元素,默认arr[0]。(就是一个平常的固定值,默以为0都可以)
2.从第二个位置开始遍历数组的元素,比较后,赋值到MAX变量中。因为是循环语句套在外面,跳出不了循环,那么会一直比较,全部的元素。大的就再次赋值,小的就继承循环。会直到循环竣事。
  1. package com.itheima.array;
  2. public class ArrayTest3 {
  3.    public static void main(String[] args) {
  4.        //数组,求最大值
  5.        int arr[] = {1,2,3,4,5,5,6,7,8,10,6};
  6.        int max = arr[0];//仅仅是一个固定值而已,赋值为数组中的一个元素,这样普遍性更强,否则如果是0,0可能是数组元素中最大或最小的。
  7.        //arr.length-1 是指数组最后一个元素
  8.        for (int i = 0; i < arr.length; i++) {
  9.            if(max < arr[i]){
  10.                max = arr[i];
  11.            }
  12.        }
  13.        System.out.println(max);
  14.    }
  15. }
复制代码

[重点]数组反转

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

  1. package com.itheima.array.cases;
  2. public class Test2 {
  3.    public static void main(String[] args) {
  4.        //1.变量互换
  5.        int a = 250;
  6.        int b = 985;
  7.        int temp = 0;
  8.        temp = a;
  9.        a = b;
  10.        b = temp;
  11.        System.out.println("a:" + a + "\n" + "b:" + b);
  12.        System.out.println("======2.数组元素互换==============");
  13.        //2.数组元素互换
  14.        //让第一个和倒数第一个互换,第二个和倒数第二个互换,第三个和倒数第三个互换...
  15.        int arr1[] = new int[]{10, 20, 30, 40, 50};
  16.        int temp1 = arr1[0];//仅仅是一个固定值,这里赋值0也可以。表示成这样,方便阅读
  17.        for (int i = 0, j = (arr1.length - 1); i < j; i++, j--) {//当i不小于j的时候进行结束,也就是刚好等于的时候
  18.            //相当于变量互换
  19.            temp1 = arr1[j];
  20.            arr1[i] = arr1[j];
  21.            arr1[i] = temp1;
  22.        }
  23.        //输出
  24.        for (int i = 0; i < arr1.length; i++) {
  25.            System.out.print(arr1[i] + "\t");
  26.        }
  27.    }
  28. }
复制代码

[难点]随机排名

  1. package com.itheima.array.cases;
  2. import java.util.Random;
  3. import java.util.Scanner;
  4. public class ArrayRandomRange_import_3 {
  5.    public static void main(String[] args) {
  6.        //非常熟练
  7. //需求:现在有五名创业者需要进行路演,他们分别有工号,但是为确保公平性,现在想随机上台路演。请你实现功能
  8.        int c_num[] = new int[5];
  9.        Scanner sc = new Scanner(System.in);
  10.        //输入5个工号
  11.        for (int i = 0; i < c_num.length; i++) {
  12.            System.out.println("请你输入第"+(i+1)+"个工号");
  13.            int num = sc.nextInt();
  14.            c_num[i] = num;
  15.        }
  16.        //随机工号
  17.        for (int j = 0; j < c_num.length; j++) {
  18.            Random r = new Random();
  19.            int ranDomIndex = r.nextInt(c_num.length);//nextInt()产生的是[0,4]与数组对应,不用[加减法]。
  20.            //交换:(以随机索引的数组)=>数组的随机的另一个元素  与 本数组元素 按照迭代顺序交换。[首位呼应一条龙]
  21.            //实际是:该数组的元素相互进行交换。
  22.            //只是ranDomIndex是独立事件,会有重复数,会重复交换,导致随机的不是很彻底。
  23.            int temp = 0;
  24.            temp = c_num[j];
  25.            c_num[j] = c_num[ranDomIndex];//先写,现在看就是数组俩元素进行交换,只是这个地方改成了ranDdonIndex
  26.            c_num[ranDomIndex] = temp;
  27.        }
  28.        
  29.        //输出
  30.        for (int k = 0; k < c_num.length; k++) {
  31.            System.out.print(c_num[k] +" ");      
  32.        }
  33.    }
  34. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

天津储鑫盛钢材现货供应商

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表