Java数组
编辑时间:2021/02/19
读完本节:大概花费40分钟,共3551词
1.数组(Array)
-
定义:数组(Array)是多个相同类型数据按一定顺序排列的集合,并使用一个一个名字作为数组名,并通过编号的方式对这些数据进行统一管理。
-
数组常见的概念
数组名(标识符);索引(下标);元素(每一个索引所对应的值);数组长度(数组所包含元素的个数)
-
数组的特点:
- 数组是有序排列的。
- 数组属于引用数据类型的变量。数组的元素既可以是基本数据类型(整型、浮点型、字符型、布尔类型)也可以是引用数据类型(类、数组、接口)。
- 创建数组对象会在内存中开辟一整块连续的空间。
- 数组的长度一旦确定,就不能修改,此时想要扩展数组的长度通常做法是重新new一个数组,然后拷贝。
-
数组的分类:
按照维数:一维数组、二维数组…二维数组以上的数组统称为多维数组
按照元素的类型:基本数据类型的数组、引用数据类型的数组
-
二维数组:
对于二维数组的理解可以堪称是一位数组array1又作为另一个数组array2的元素而存在。即理解为外层数组的元素是引用数据类型,这个引用数据类型就是类array,其实从数组底层的运行机制来看,并不存在多维数组,仅仅只是一维数组的扩展使用。
2.数组的使用
-
一维数组的使用
-
一维数组的声明和初始化
-
数组的声明
//一维数组的声明 int[] id;
-
静态初始化:数组的初始化和赋值操作同时进行
//在声明的同时可以直接初始化,也可以先声明再初始化 //同变量相同的是无论是直接初始化,还是先声明再初始化,都需要对声明的数组进行初始化 //声明的同时初始化 int[] id1 = new int[]{1,2,3,4,5};//声明为int类型,并初始化 //或先声明在初始化 long[] id2;//声明为long类型 id2 = new long[]{1,2,3,4};//初始化
-
动态初始化:数组的初始化和赋值操作分开进行
//动态初始化 //声明的同时初始化 String[] str = new String[4];//声明为String类型,并初始化内存空间 //或先声明在初始化 double[] id2;//声明为double类型 id2 = new double[4];//初始化
-
补充
-
常见的错误写法
int arr1 = new int[]; int[5] arr2 =new int[5]; int[] arr3 = new int[3]{1,2,3};
-
不常见的正确写法
int[] arr = {1,2,3,4};//自动将arr类型推断为int型 //若先声明后初始化的化则不能省略,如下是错误的 int[] arr; arr = {1,2,3,4}
-
从上述的静态初始化和动态初始化可以看出,在初始化完成之后,数组的长度就被确定了,因为不确定长度就无法在内存中开辟相应的空间进行操作。
-
-
-
调用一维数组的指定位置的元素
通过索引的方式调用指定位置的元素,数组的索引是从0开始的,到数组的长度减一结束。
//对上面定义的str数组赋值 str[0] = "1"; str[1] = "2"; str[2] = "3"; str[3] = "4"; //str[4] = "5";//编译可通过,但运行时报数组越界的错误 //输出处于第一位的元素 System.out.print(str[0]);
-
获取一维数组的长度
使用数组的属性:length
System.out.print(str[].length);//4 System.out.print(id1[]);//5
-
遍历一维数组
通常使用for循环进行数组索引的遍历
//遍历打印数组 for(int i = 0;i < str[].length;i++){ System.out.print(str[i]); }
-
-
多维数组的使用(二维举例,更高的类同)
-
二维数组的声明和初始化
-
数组的声明
int[][] arr;
-
静态初始化
//静态初始化 //先声明后初始化 int[][] arr1; arr1 = new int[][]{{1,2,3}{4,5,6}{7,8}}; //声明的同时初始化 int[][] arr2 = new int[][]{{1,2,3}{4,5,6}{7,8}};
-
动态初始化
//动态初始化 //先声明后初始化(略) //声明的同时初始化 //动态初始化1 int[][] arr3 = int[3][2]; //动态初始化2 String[][] arr4 = String[3][];
-
补充
-
常见的错误写法
String[][] arr5 = new String[][5]; String[2][3] arr6 = new String[][]; String[][] arr7 = new String[3][2]{{1,2}{3,4}{5,6}};
-
不常见的正确写法
int[] arr8[] = new int[][]{{1}{2,3}{4,5,6}}; int[] arr9[] = {{1}{2,3}{4,5,6}};//类型推断
-
-
-
调用二维数组的指定位置元素
类同一维使用索引。
//打印输出 System.out.print(arr1[0][0]);//打印输出arr1的第一位元素 System.out.print("\n"); int[][] arr2 = new int[][]{{1,2,3}{4,5,6}{7,8}}; System.out.print(arr2[2][2]);//输出arr2的[2][2]号元素,未赋值因此是0
-
获取二维数组的长度
使用数组的length属性
//二维或多维元素有内层和外层之分 int[][] arr2 = new int[][]{{1,2,3}{4,5,6}{7,8}}; //打印输出二维数组外层的长度 System.out.print(arr2.length);//3 //打印输出二维数组的内层长度 System.out.print(arr2[1].length);//3 System.out.print(arr2[2].length);//2
-
遍历二维数组
通常使用for循环的嵌套
//遍历输出二维数组arr2 int[][] arr2 = new int[][]{{1,2,3}{4,5,6}{7,8}}; for(int i = 0;i < arr2.length;i++){//外层元素 for(int j = 0;j < arr2[i].length;j++){//内层元素 System.out.print(arr2[i][j]); } System.out.print("\n");//控制换行 }
-
3.数组的默认初始化值
-
一维数组的默认初始化值
所有整型(byte、short、int、long)数组默认初始化值是0,浮点型(double、float)数组默认初始化值是0.0,字符型数组默认初始化值是ASCII标号为0的字符(或为\u0000,而非‘0’),引用数据类型(String)型数组默认初始化值是null(不是“null”)。布尔型数组的默认初始化值是false(在java中用0表示false用1表示true)。
//一维数组默认初始化值输出 public class ArrayTest{ public static void main(String[] args){ //使用动态初始化确保不被静态初始化所后续赋值所干扰 int[] arr0 = new int[2]; System.out.println(arr0[0]);//0 short[] arr1 = new short[2]; System.out.println(arr1[0]);//0 byte[] arr2 = new byte[2]; System.out.println(arr2[0]);//0 long[] arr3 = new long[2]; System.out.println(arr3[0]);//0 double[] arr4 = new double[2]; System.out.println(arr4[0]);//0.0 float[] arr5 = new float[2]; System.out.println(arr5[0]);//0.0 char[] arr6 = new char[2]; System.out.println(arr6[0]);//'/u0000'所表示的字符 String[] arr7 = new String[2]; System.out.println(arr[7]);//null boolean[] arr8 = new boolean[2]; System.out.println(arr8[0]);//false } }
-
二维数组的默认初始化值
对于动态初始化方式一:外层元素默认初始化值是地址值,内层元素默认初始化值与一维数组情况相同。
对于动态初始化方式二:外层元素默认初始化值是null,内层元素默认初始化值不存在,若调用控制台报空指针异常。
//二维数组的默认初始化值 public class ArrayTest1{ public static void main(String[] args){ int[][] arr0 = new int[3][4]; System.out.println(arr0[0]); //I@15db9742 I表示int型数组,@后面是数组的外层第一位元素在内存中的位置 System.out.println(arr0[0][0]); //0和一维数组一样 float[][] arr1 = new float[4][3]; System.out.println(arr1[0]); //F@6d06d69c F表示float型数组,@后面是数组的外层第一位元素在内存中的位置 System.out.println(arr1[0][0]); //0.0和一维数组一样 String[][] arr2 = new String[4][3]; System.out.println(arr2[0]); //Ljava.lang.String;@7852e922 //@前表示的是类String,是引用类型的数组,@后面是数组的外层第一位元素在内存中的位置 System.out.println(arr2[0][0]); //null和一维数组一样 //二维数组的 动态初始化值2 double[][] arr3 = new double[4][]; System.out.println(arr3[0]); //null //原因是外层只分配了4个元素,但是内层元素内容并未给出,因此为null System.out.println(arr3[1][0]); //NullPointerExcetption空指针异常 //原因是外层的第二个元素并没有对其再确定内层的内容,因此内存中没有其指向的地址,所以空指针 } }
4.数组的内存解析
-
内存的简化结构
-
一维数组的内存解析
此处的地址值是jvm虚拟算出的哈希值,屏蔽了底层真实的内存地址
arr数组再内存中初始化并赋上默认初始化值
arr数组更改默认初始化值为用户定义值{1,2,3}
执行第二句初始化并赋上默认值
arr1数组更改默认初始化值为用户定义值,这里的arr1[1]和arr1[2]存储的值应当存放再常量池中,此处为了便于演示,直接写在旁边。
执行最后一句,重新为arr1分配新的内存空间
随后的某一个时间点,取消连接的“地址b”在堆区因为没有在栈区找到被引用所以随后java垃圾回收机制将其自动销毁
在执行完所有语句之后处于栈区的数组依次出栈,栈区清空后,堆区中开辟出的空间会在某一个时间点被java垃圾回收机制销毁
-
二维数组的内存解析
arr1数组再内存中初始化并赋上默认初始化值
执行第二句,将arr1[1]的值更改为用户定义值
执行第三句,为arr1[2]申请新的内存空间
执行最后一句,为arr1[2][1]赋上30
在执行完所有语句之后处于栈区的数组依次出栈,栈区清空后,堆区中开辟出的空间会在某一个时间点被java垃圾回收机制销毁
5.练习
-
一维数组练习
//从键盘读入学生成绩,找出最高分,并输出学生成绩等级 /* 成绩 >= 最高分-10 等级为A 成绩 >= 最高分-20 等级为B 成绩 >= 最高分-30 等级为C 其余 等级为D */ import java.util.Scanner; public class ArrayTest { public static void main(String[] args){ //获取学生人数 System.out.print("Enter student number: "); Scanner scan = new Scanner(System.in); int stuNumber = scan.nextInt(); System.out.println("Enter " + stuNumber + " students score:"); //初始化最高分 int maxScore = 0; //创建int数组保存学生成绩 //创建数组,动态初始化 int[] score = new int[stuNumber]; //给数组中的元素赋值 for(int i = 0;i < score.length;i++){ score[i] = scan.nextInt(); //判断并比较等级,优化 if(score[i] > maxScore){ maxScore = score[i]; } } //输出最高分 System.out.println("The highest score is: " + maxScore); // //判断并比较等级 // for(int i = 0;i < score.length;i++){ // if(score[i] > maxScore){ // maxScore = score[i]; // } // } //判断学生成绩等级并输出 char level; for(int i = 0;i < score.length;i++){ if(maxScore - score[i] <= 10){ level = 'A'; }else if(maxScore - score[i] <= 20){ level = 'B'; }else if(maxScore - score[i] <= 30){ level = 'C'; }else{ level = 'D'; } System.out.println("Student " + i + "score is " + score[i] + "grade is " + level); } } }
-
二维数组练习
练习1:获取arr数组中的所有元素和
j = 0 j = 1 j = 2 j = 3 i = 0 3 5 8 - i = 1 12 9 - - i = 2 7 0 6 4 public class ArrayTest{ public static void main(String[] args){ int[][] arr = new int[][]{{3,5,8},{12,9},{7,0,6,4}}; int sum = 0; for(int i = 0;i < arr.length;i++){ for(int j = 0;j < arr[i].length;j++){ sum += arr[i][j]; } } System.out.println("总和为:" + sum); } }
练习2:判断能否通过编译
//声明: int[] x,y[]; //在给x,y变量赋值以后,能够通过编译的是 //分析:int[] x,y[];等价于int[] x; int[][] y; //所以x是int型的一维数组,y是int型的二维数组 x[0] = y; //把二维数组赋值给一维数组的元素 false y[0] = x; //把一维数组赋值给二维数组的外层元素 true y[0][0] = x; //把一维数组赋值给二维数组的内层元素 true x[0][0] = y; //一维数组x没有内层元素 false y[0][0] = x[0]; //二维数组的内层元素赋值为一维数组的元素值 true x = y; //一维数组赋值为二维数组 false
练习3:使用二维数组打印一个10行的杨辉三角
public class yangHui{ public static void main(String[] args){ /* * 杨辉三角: * 1. 第一行有一个元素,第n行有n个元素 * 2. 每一行的第一个元素和最后一个元素都是1 * 3. 从第三行开始,对于非第一个元素和最后一个元素有 * 该元素 = 上一行同列元素的前一个元素 + 上一行同列元素 即: * yangHui[i][j] = yangHui[i - 1][j - 1] + yangHui[i - 1][j]; * * */ //1. 声明并初始化二维数组 int[][] yangHui = new int[10][]; //2. 给数组元素赋值 for(int i = 0;i < yangHui.length;i++){//外层循环遍历10行 //每一行只有i + 1个元素,数组下标从0开始 yangHui[i] = new int[i + 1]; //给首末元素赋值 yangHui[i][0] = yangHui[i][i] = 1; //给其余元素赋值 方法1 // for(int j = 0;j < yangHui[i].length;j++){//直接遍历内层元素 // if(yangHui[i][j] != 1){//给内层不等于1的元素重新赋值 // yangHui[i][j] = yangHui[i - 1][j - 1] + yangHui[i - 1][j]; // } // } //给其余元素赋值 方法2 //if(i > 0) { //可以去掉if判断的原因是就算i = 0进到for循环中也会因为不满足for循环条件而自动结束本次i的循环 for (int j = 1; j < yangHui[i].length - 1; j++) {//j的范围刚好排除掉了首末元素 yangHui[i][j] = yangHui[i - 1][j - 1] + yangHui[i - 1][j]; } //} } //3. 遍历二维数组 for(int i = 0;i < yangHui.length;i++){ for(int j = 0;j < yangHui[i].length;j++){ System.out.print(yangHui[i][j] + "\t"); } System.out.println(); } } }