一、数组的概念
- 数组概念: 数组就是用于存储数据的长度固定的容器,保证多个数据的数据类型要一致。
百度百科中对数组的定义:
所谓数组(array),就是相同数据类型的元素按一定顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,以便统一管理他们,然后用编号区分他们,这个名字称为数组名,编号称为下标或索引(index)。组成数组的各个变量称为数组的元素(element)。数组中元素的个数称为数组的长度(length)。
数组的特点:
1、数组的长度一旦确定就不能修改
2、创建数组时会在内存中开辟一整块连续的空间
3、存取元素的速度快,因为可以通过[下标],直接定位到任意一个元素
二、数组的声明与初始化
//推荐
元素的数据类型[] 二维数组的名称;
//不推荐
元素的数据类型 二维数组名[];
方式一:静态初始化
数据类型[] 数组名 = {元素1,元素2,元素3...};//必须在一个语句中完成,不能分开两个语句写
方式二:静态初始化
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3...};
或
数据类型[] 数组名;
数组名 = new 数据类型[]{元素1,元素2,元素3...};
方式三:动态初始化
数组存储的元素的数据类型[] 数组名字 = new 数组存储的元素的数据类型[长度]; 或 数组存储的数据类型[] 数组名字; 数组名字 = new 数组存储的数据类型[长度];
数组定义格式详解:
数组存储的元素的数据类型: 创建的数组容器可以存储什么数据类型的数据
元素的类型可以是任意的Java的数据类型。例如:int, String, Student等
[] : 表示数组
数组名字:为定义的数组起个变量名,满足标识符规范,可以使用名字操作数组
new:关键字,创建数组使用的关键字。因为数组本身是引用数据类型,所以要用new创建数组对象
[长度]:数组的长度,表示数组容器中可以存储多少个元素
注意:数组有定长特性,长度一旦指定,不可更改
和水杯道理相同,买了一个2升的水杯,总容量就是2升,不能多也不能少
三、数组元素的访问
索引: 每一个存储到数组的元素,都会自动的拥有一个编号,从0开始,这个自动编号称为数组索引(index),可以通过数组的索引访问到数组中的元素。
索引范围:[0, 数组的长度-1]
数组名[索引]
- 索引访问数组中的元素:
数组名[索引]=数值,为数组中的元素赋值
变量=数组名[索引],获取出数组中的元素
1 public static void main(String[] args) { 2 //定义存储int类型数组,赋值元素1,2,3,4,5 3 int[] arr = {1,2,3,4,5}; 4 //为0索引元素赋值为6 5 arr[0] = 6; 6 //获取数组0索引上的元素 7 int i = arr[0]; 8 System.out.println(i); 9 //直接输出数组0索引元素 10 System.out.println(arr[0]); 11 }
四、数组的遍历
数组的长度属性: 每个数组都具有长度,而且是固定的,Java中赋予了数组的一个属性,可以获取到数组的长度,语句为:
数组名.length
,属性length的执行结果是数组的长度,int类型结果。由次可以推断出,数组的最大索引值为数组名.length-1
数组遍历: 将数组中的每个元素分别获取出来,就是遍历。遍历也是数组操作中的基石
1 public static void main(String[] args) { 2 int[] arr = new int[]{1,2,3,4,5}; 3 //打印数组的属性,输出结果是5 4 System.out.println("数组的长度:" + arr.length); 5 6 //遍历输出数组中的元素 7 System.out.println("数组的元素有:"); 8 for(int i=0; i<arr.length; i++){ 9 System.out.println(arr[i]); 10 } 11 }
五、数组元素的默认值
数组存储的元素的数据类型[] 数组名字 = new 数组存储的元素的数据类型[长度];
六、数组内存图
6.1 内存概述
内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来。我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。
Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。
6.2 Java虚拟机的内存划分
为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
区域名称 | 作用 |
程序计数器 | 程序计数器是CPU中的寄存器,它包含每一个线程下一条要执行的指令的地址 |
本地方法栈 | 当程序中调用了native的本地方法时,本地方法执行期间的内存区域 |
方法区 | 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据 |
堆内存 | 存储对象(包括数组对象),new来创建的,都存储在堆内存 |
虚拟机栈 | 用于存储正在执行的每个Java方法的局部变量表等。局部变量表存放了编译期可知长度的各种基本数据类型、对象引用,方法执行完,自动释放 |
6.3 数组在内存中的存储
6.3.1 一个数组内存图
1 public static void main(String[] args) { 2 int[] arr = new int[3]; 3 System.out.println(arr);//[I@5f150435 4 } 5
6.3.2 数组下标为什么是0开始
因为第一个元素距离数组首地址间隔0个单元
6.3.3 两个数组内存图
1 public static void main(String[] args) { 2 int[] arr = new int[3]; 3 int[] arr2 = new int[2]; 4 System.out.println(arr); 5 System.out.println(arr2); 6 } 7
6.3.4 两个变量指向一个数组
1 public static void main(String[] args) { 2 // 定义数组,存储3个元素 3 int[] arr = new int[3]; 4 //数组索引进行赋值 5 arr[0] = 5; 6 arr[1] = 6; 7 arr[2] = 7; 8 //输出3个索引上的元素值 9 System.out.println(arr[0]); 10 System.out.println(arr[1]); 11 System.out.println(arr[2]); 12 //定义数组变量arr2,将arr的地址赋值给arr2 13 int[] arr2 = arr; 14 arr2[1] = 9; 15 System.out.println(arr[1]); 16 } 17
七、二维数组
二维数组:本质上就是元素为一维数组的一个数组。
二维数组的标记:[][]
int[][] arr; //arr是一个二维数组,可以看成元素是int[]一维数组类型的一个数组
二维数组也可以看成一个二维表,行*列组成的二维表,只不过这个二维表,每一行的列数还可能不同。但是每一个单元格中的元素的数据类型是一致的,例如:都是int,都是String等
7.1 二维数组的声明与初始化
//推荐 元素的数据类型[][] 二维数组的名称; //不推荐 元素的数据类型 二维数组名[][]; //不推荐 元素的数据类型[] 二维数组名[];
7.1.1 静态初始化
元素的数据类型[][] 二维数组名 = new 元素的数据类型[][]{ {元素1,元素2,元素3 。。。}, {第二行的值列表}, ... {第n行的值列表} }; 元素的数据类型[][] 二维数组名; 二维数组名 = new 元素的数据类型[][]{ {元素1,元素2,元素3 。。。}, {第二行的值列表}, ... {第n行的值列表} }; //以下格式要求声明与静态初始化必须一起完成 元素的数据类型[][] 二维数组的名称 = { {元素1,元素2,元素3 。。。}, {第二行的值列表}, ... {第n行的值列表} };
7.1.2 动态初始化(规则二维表:每一行的列数是相同的)
//(1)确定行数和列数 元素的数据类型[][] 二维数组名 = new 元素的数据类型[m][n]; m:表示这个二维数组有多少个一维数组。或者说一共二维表有几行 n:表示每一个一维数组的元素有多少个。或者说每一行共有一个单元格 //此时创建完数组,行数、列数确定,而且元素也都有默认值 //(2)再为元素赋新值 二维数组名[行下标][列下标] = 值;
1 public static void main(String[] args) { 2 //定义一个二维数组 3 int[][] arr = new int[3][2]; 4 5 //定义了一个二维数组arr 6 //这个二维数组有3个一维数组的元素 7 //每一个一维数组有2个元素 8 //输出二维数组名称 9 System.out.println(arr); //地址值 [[I@175078b 10 11 //输出二维数组的第一个元素一维数组的名称 12 System.out.println(arr[0]); //地址值 [I@42552c 13 System.out.println(arr[1]); //地址值 [I@e5bbd6 14 System.out.println(arr[2]); //地址值 [I@8ee016 15 16 //输出二维数组的元素 17 System.out.println(arr[0][0]); //0 18 System.out.println(arr[0][1]); //0 19 20 //... 21 }
7.1.3 动态初始化(不规则:每一行的列数可能不一样)
//(1)先确定总行数 元素的数据类型[][] 二维数组名 = new 元素的数据类型[总行数][]; //此时只是确定了总行数,每一行里面现在是null //(2)再确定每一行的列数,创建每一行的一维数组 二维数组名[行下标] = new 元素的数据类型[该行的总列数]; //此时已经new完的行的元素就有默认值了,没有new的行还是null //(3)再为元素赋值 二维数组名[行下标][列下标] = 值;
1 public static void main(String[] args) { 2 //定义数组 3 int[][] arr = new int[3][]; 4 5 System.out.println(arr); //[[I@175078b 6 7 System.out.println(arr[1][0]);//NullPointerException 8 System.out.println(arr[0]); //null 9 System.out.println(arr[1]); //null 10 System.out.println(arr[2]); //null 11 12 //动态的为每一个一维数组分配空间 13 arr[0] = new int[2]; 14 arr[1] = new int[3]; 15 arr[2] = new int[1]; 16 17 System.out.println(arr[0]); //[I@42552c 18 System.out.println(arr[1]); //[I@e5bbd6 19 System.out.println(arr[2]); //[I@8ee016 20 21 System.out.println(arr[0][0]); //0 22 System.out.println(arr[0][1]); //0 23 //ArrayIndexOutOfBoundsException 24 //System.out.println(arr[0][2]); //错误 25 26 arr[1][0] = 100; 27 arr[1][2] = 200; 28 }
7.2 二维数组的相关名称及其表示方式
(1)二维数组的长度/行数:
二维数组名.length
(2)二维数组的某一行:
二维数组名[行下标]
行下标的范围:[0, 二维数组名.length-1]
(3)某一行的列数:
二维数组名[行下标].length
因为二维数组的每一行是一个一维数组
(4)某一个元素
二维数组名[行下标][列下标]
7.3 二维数组的遍历
1 for(int i=0; i<二维数组名.length; i++){ 2 for(int j=0; j<二维数组名[i].length; j++){ 3 System.out.print(二维数组名[i][j]); 4 } 5 System.out.println(); 6 }
7.4 数组操作的常见异常
7.4.1 数组越界异常
1 public static void main(String[] args) { 2 int[] arr = {1,2,3}; 3 System.out.println(arr[3]); 4 }
创建数组,赋值3个元素,数组的索引就是0,1,2,没有3索引,因此不能访问数组中不存在的索引,程序运行后,将会抛出 ArrayIndexOutOfBoundsException
数组越界异常。在开发中,数组的越界异常是不能出现的,一旦出现了,就必须要修改编写的代码
7.4.2 数组空指针异常
1 public static void main(String[] args) { 2 //定义数组 3 int[][] arr = new int[3][]; 4 5 System.out.println(arr[0][0]);//NullPointerException 6 }
数组的每一行还未分配具体存储元素的空间,arr[0]是null,访问arr[0][0]会抛出NullPointerException
空指针异常