:数组的定义与使用)
目录一数组的基本概念1.为什么要使⽤数组2.什么是数组3.数组的创建及初始化数组的创建数组的初始化4.数组的基本使⽤二数组是引⽤类型1.初始JVM的内存分布2.基本类型变量与引⽤类型变量的区别3.再谈引⽤变量4.认识null三数组的应⽤场景1.保存数据2.作为函数的参数3.作为函数的返回值四操作数组⼯具类Arrays1.数组转字符串2.数组拷⻉3.数组排序(冒泡排序五⼆维数组1.普通的⼆维数组2.不规则的⼆维数组本文章大纲本文介绍了Java数组的基本概念和使用方法。主要内容包括1. 数组的定义与作用用于存储多个相同类型的数据2. 数组的创建和初始化方式包括动态初始化和静态初始化3. 数组的基本操作如元素访问、修改和遍历4. 数组的内存分配机制解释基本类型变量与引用类型变量的区别5. 数组的应用场景包括作为函数参数和返回值6. 数组工具类Arrays的使用包括数组转字符串、拷贝和排序7. 二维数组的定义和使用方法。文章通过代码示例详细说明了数组的各种操作并强调了使用数组时需要注意的问题如数组越界等。一数组的基本概念1.为什么要使⽤数组假设现在要存5个学⽣的javaSE考试成绩并对其进⾏输出按照之前掌握的知识点我们会写出如下 代码public static void main(String[] args) { int score1 70; int score2 80; int score3 85; int score4 60; int score5 90; System.out.println(score1); System.out.println(score2); System.out.println(score3); System.out.println(score4); System.out.println(score5); }上述代码没有任何问题但不好的是如果有20名同学成绩呢需要创建20个变量吗有100个学⽣ 的成绩那不得要创建100个变量。仔细观察这些学⽣成绩发现所有成绩的类型都是相同的那Java中 存在可以存储多个相同类型的数据吗这就是本节要讲的数组2.什么是数组数组可以看成是相同类型元素的⼀个集合。在内存中是⼀段连续的空间。⽐如现实中的⻋库在Java中包含6个整型类型元素的数组就相当于上图中连在⼀起的6个⻋位从上图中可以看到数组的空间是连在⼀起的每个空间有⾃⼰的编号起始位置的编号为0即数组的下标。那在程序中如何创建数组呢3.数组的创建及初始化数组的创建T [ ] 数组名 new T[N];T表⽰数组中存放元素的类型T[ ]表⽰数组的类型N表⽰数组的⻓度public static void main(String[] args) { int[] array1 new int[10];//创建⼀个可以容纳10个int类型元素的数组 double[] array2 new double[5]; //创建⼀个可以容纳5个double类型元素的数组 String[] array3 new String[3]; //创建⼀个可以容纳3个字符串元素的数组 }数组的初始化数组的初始化主要分为动态初始化以及静态初始化。1.动态初始化在创建数组时直接指定数组中元素的个数int[ ] array new int[10];2.静态初始化在创建数组时不直接指定数据元素个数⽽直接将具体的数据内容进⾏指定语法格式T[ ] 数组名称 {data1, data2, data3, ..., datan};int[ ] array1 new int[ ]{0,1,2,3,4,5,6,7,8,9};double[ ] array2 new double[ ]{1.0, 2.0, 3.0, 4.0, 5.0};String[ ] array3 new String[ ]{hell, Java, !!!};【注意事项】静态初始化虽然没有指定数组的⻓度编译器在编译时会根据{ }中元素个数来确定数组的⻓度。静态初始化时,{ }中数据类型必须与[ ]前数据类型⼀致。静态初始化可以简写省去后⾯的newT[ ]省去后面的new和C语言有点像只不过括号的位置不一样int[] array1 {0,1,2,3,4,5,6,7,8,9};double[] array2 {1.0, 2.0, 3.0, 4.0, 5.0};String[] array3 {hell, Java, !!!};数组也可以按照如下C语⾔⽅式创建不推荐int arr[] {1, 2, 3};静态和动态初始化也可以分为两步但是省略格式不可以。public static void main(String[] args) { int[] array1; array1 new int[10]; int[] array2; array2 new int[]{10, 20, 30}; }注意省略格式不可以拆分 , 否则编译失败这种⽅式只能在定义的同时初始化int[] array3;array3 {1, 2, 3};如果没有对数组进⾏初始化数组中元素有其默认值如果数组中存储元素类型为基类类型默认值为基类类型对应的默认值⽐如如果数组中存储元素类型为引⽤类型默认值为nullString[] words new String[3];4.数组的基本使⽤数组中元素访问数组在内存中是⼀段连续的空间空间的编号都是从0开始的依次递增该编号称为数组的下标数 组可以通过下标访问其任意位置的元素。⽐如public static void main(String[] args) { int[]array new int[]{10, 20, 30, 40, 50}; System.out.println(array[0]); System.out.println(array[1]); System.out.println(array[2]); System.out.println(array[3]); System.out.println(array[4]); }输出也可以通过 [ ] 对数组中的元素进⾏修改array[0] 100;System.out.println(array[0]);输出【注意事项】数组是⼀段连续的内存空间因此⽀持随机访问即通过下标访问快速访问数组中任意位置的元素下标从0开始介于[0,N之间不包含NN为元素个数不能越界否则会报出下标越界异常。越界的情况public static void main(String[] args) { int[] array {1, 2, 3}; System.out.println(array[3]); }结果报错使⽤数组⼀定要注意下标的访 问谨防越界.遍历数组所谓遍历是指将数组中的所有元素都访问⼀遍,访问是指对数组中的元素进⾏某种操作⽐如打 印。public static void main(String[] args) { int[]array new int[]{10, 20, 30, 40, 50}; System.out.println(array[0]); System.out.println(array[1]); System.out.println(array[2]); System.out.println(array[3]); System.out.println(array[4]); }上述代码可以起到对数组中元素遍历的⽬的但问题是如果数组中增加了⼀个元素就需要增加⼀条打印语句如果输⼊中有100个元素就需要写100个打印语句如果现在要把打印修改为给数组中每个元素加1修改起来⾮常⿇烦通过观察代码可以发现对数组中每个元素的操作都是相同的则可以使⽤循环来进⾏打印。public static void main(String[] args) { int[]array new int[]{10, 20, 30, 40, 50}; for(int i 0; i 5; i){ System.out.println(array[i]); } }输出改成循环之后上述三个缺陷可以全部2和3问题可以全部解决但是⽆法解决问题1。那能否获取到数 组的⻓度呢注意在数组中可以通过 数组对象 .length 来获取数组的⻓度public static void main(String[] args) { int[]array new int[]{10, 20, 30, 40, 50}; for(int i 0; i array.length; i){ System.out.println(array[i]); } }输出也可以使⽤for-each遍历数组public static void main(String[] args) { int[] array {1, 2, 3}; for (int x : array) { System.out.println(x); } }输出for-each 是for 循环的另外⼀种使⽤⽅式.能够更⽅便的完成对数组的遍历.可以避免循环条件和更新语句写错.二数组是引⽤类型1.初始JVM的内存分布内存是⼀段连续的存储空间主要⽤来存储程序运⾏时数据的。⽐如程序运⾏时代码需要加载到内存程序运⾏产⽣的中间数据要存放在内存程序中的常量也要保存有些数据可能需要⻓时间存储⽽有些数据当⽅法运⾏结束后就要被销毁如果对内存中存储的数据不加区分的随意存储那对内存管理起来将会⾮常⿇烦。因此JVM也对所使⽤的内存按照功能的不同进⾏了划分程序计数器(PCRegister):只是⼀个很⼩的空间,保存下⼀条执⾏的指令的地址虚拟机栈(JVMStack):与⽅法调⽤相关的⼀些信息每个⽅法在执⾏时都会先创建⼀个栈帧栈 帧中包含有局部变量表、操作数栈、动态链接、返回地址以及其他的⼀些信息保存的都是与⽅ 法执⾏时相关的⼀些信息。⽐如局部变量。当⽅法运⾏结束后栈帧就被销毁了即栈帧中保存 的数据也被销毁了。本地⽅法栈(NativeMethodStack):本地⽅法栈与虚拟机栈的作⽤类似.只不过保存的内容是 Native⽅法的局部变量.在有些版本的JVM实现中(例如HotSpot),本地⽅法栈和虚拟机栈是⼀起的堆(Heap):JVM所管理的最⼤内存区域.使⽤new创建的对象都是在堆上保存(例如前⾯的 new int[]{1, 2, 3} )堆是随着程序开始运⾏时⽽创建随着程序的退出⽽销毁堆中的数据只 要还有在使⽤就不会被销毁⽅法区(MethodArea):⽤于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后 的代码等数据.⽅法编译出的的字节码就是保存在这个区域现在我们只简单关⼼堆和虚拟机栈这两块空间后续JVM中还会更详细介绍。2.基本类型变量与引⽤类型变量的区别基本数据类型创建的变量称为基本变量该变量空间中直接存放的是其所对应的值⽽引用数据类型创建的变量⼀般称为对象的引⽤其空间中存储的是对象所在空间的地址public static void func() { int a 10; int b 20; int[] arr new int[]{1,2,3}; }在上述代码中a、b、arr都是函数内部的变量因此其空间都在main⽅法对应的栈帧中分配a、b是内置类型的变量因此其空间中保存的就是给该变量初始化的值array是数组类型的引⽤变量其内部保存的内容可以简单理解成是数组在堆空间中的⾸地址从上图可以看到引⽤变量并不直接存储对象本⾝可以简单理解成存储的是对象在堆中空间的起始 地址。通过该地址引⽤变量便可以去操作对象。有点类似C语⾔中的指针但是Java中引⽤要⽐指针 的操作更简单。3.再谈引⽤变量public static void func1() { int[] array1 new int[3]; array1[0] 10; array1[1] 20; array1[2] 30; int[] array2 new int[]{1,2,3,4,5}; array2[0] 100; array2[1] 200; array1 array2; array1[2] 300; array1[3] 400; array2[4] 500; for (int i 0; i array2.length; i) { System.out.println(array2[i]); } }图片解析4.认识nullnull 在Java中表⽰空引⽤,也就是⼀个不指向对象的引⽤int[] arr null; System.out.println(arr[0]);输出null 的作⽤类似于C语⾔中的NULL(空指针),都是表⽰⼀个⽆效的内存位置.因此不能对这个内存进⾏ 任何读写操作.⼀旦尝试读写,就会抛出NullPointerException注意java的null和0号地址并没有一定的关联三数组的应⽤场景1.保存数据public static void main(String[] args) { int[] array {1, 2, 3}; for(int i 0; i array.length; i){ System.out.println(array[i] ); } }输出2.作为函数的参数参数传基本数据类型public static void main(String[] args) { int num 0; func(num); System.out.println(num num); } public static void func(int x) { x 10; System.out.println(x x); }输出发现在func⽅法中修改形参x的值,不影响实参的num值.形参的改变不会影响实参参数传数组类型(引⽤数据类型)public static void main(String[] args) { int[] arr {1, 2, 3}; func(arr); System.out.println(arr[0] arr[0]); } public static void func(int[] a) { a[0] 10; System.out.println(a[0] a[0]); }输出发现在func⽅法内部修改数组的内容,⽅法外部的数组内容也发⽣改变.因为数组是引⽤类型按照引⽤类型来进⾏传递是可以修改其中存放的内容的。3.作为函数的返回值⽐如获取斐波那契数列的前N项public static void main(String[] args) { int[] array fib(10); for (int i 0; i array.length; i) { System.out.println(array[i]); } } public static int[] fib(int n){ if(n 0){ return null; } int[] array new int[n]; array[0] array[1] 1; for(int i 2; i n; i){ array[i] array[i-1] array[i-2]; } return array; }输出四操作数组⼯具类Arrays1.数组转字符串使用Arrays 中 toString完成转换public static void main(String[] args) { int[] arr {1,2,3,4,5,6}; String arr2 Arrays.toString(arr); System.out.println(arr2); }输出使⽤这个⽅法后续打印数组就更⽅便⼀些.Java 中提供了java.util.Arrays 包,其中包含了⼀些操作数组的常⽤⽅法.2.数组拷⻉使⽤ Arrays 中 copyof ⽅法完成数组的拷⻉public static void main(String[] args) { int[] arr {1,2,3,4,5,6}; //int[] newArr arr; int[] newArr Arrays.copyOf(arr, arr.length); System.out.println(newArr: Arrays.toString(newArr)); }输出注意数组当中存储的是基本类型数据时不论怎么拷⻉基本都不会出现什么问题但如果存储的是 引⽤数据类型拷⻉时需要考虑深浅拷⻉的问题关于深浅拷⻉在后续详细给⼤家介绍3.数组排序(冒泡排序使用Arrays.sort进行自动排序public static void main(String[] args) { int[] arr {9, 5, 2, 7}; Arrays.sort(arr); System.out.println(Arrays.toString(arr)); }输出关于Arrays.sort 的具体实现算法,我们在后⾯的排序算法课上再详细介绍.到时候我们会介绍很多种常 ⻅排序算法五⼆维数组1.普通的⼆维数组⼆维数组本质上也就是⼀维数组,只不过每个元素⼜是⼀个⼀维数组.基本语法数据类型 [ ][ ] 数组名称 new 数据类型 [ ⾏数 ][ 列数 ] { 初始化数据 };注意行不可以省略列可以省略打印二维数组//二维数组打印 public static void main(String[] args) { int[][]arr{{1,2,3},{3,4,5},{3,5,6}}; //三行两列 for (int i 0; i arr.length; i) { for (int j 0; j arr[i].length; j) { System.out.print(arr[i][j] ); } System.out.println(); } }输出⼆维数组是特殊的⼀维数组⼀维数组的每个元素⼜是⼀个数组arr.length 代表⼆维数组的⾏数arr[i].length 代表⼆维数组的列数2.不规则的⼆维数组不规则的⼆维数组指的是⼆维数组的列在定义的时候没有确定。public static void main(String[] args) { int[][] array new int[2][]; array[0] new int[3]; array[1] new int[5]; }上述⼆维数组就不是⼀个规则的⼆维数组。第1⾏有3列第2⾏有5列。