模块五. 数组
第一章. 数组
1. 定义数组
1. 问题:如果我们想存储一个数据,我们可以使用变量,但是变量一次只能存储一个数据,所以我们想能不能一次存储多个数据 2. 数组概述:是一个容器,数组本身属于引用数据类型 3. 作用:一次存储多个数据 4. 特点: a. 既可以存储基本类型的数据,还能存储引用类型的数据 b. 定长(定义数组时长度为多长,最多能存多少个数据)//数组最大的特点也是缺点 5. 定义: a. 动态初始化:在定义数组的时候,我们没有给具体的数据,只指定了长度 数据类型[] 数组名 = new 数据类型[长度]; int[] arr = new int[3]; 或 数据类型 数组名[] = new 数据类型[长度]; 各部分解释: 等号左边的数据类型:规定了数组中只能存储什么类型的数据 []:代表的是数组,一个[]代表一维数组,[][]代表二维数组 数组名:自己取名字(小驼峰式) new:代表的是创建数组 等号右边的数据类型:要和等号左边的数据类型一致 [长度]:指定数组长度,规定了数组最多能存多少个数据,可以少存,但不能多存 b. 静态初始化:在定义数组的时候,我们直接给了数据 数据类型[] 数组名 = new 数据类型[]{元素1,元素2,...} -> 不推荐使用 或 数据类型[] 数组名 = new 数据类型[]{元素1,元素2,...} -> 不推荐使用 或 简化的静态初始化 数据类型[] 数组名 = {元素1,元素2,...} -> 推荐使用 6. 动态初始化和静态初始化区别: a. 动态初始化:定义的时候只指定了长度,没有存具体的数据 当只知道长度,不知道具体存啥具体的数据时可以使用动态的初始化 b. 静态初始化:定义的时候就直接知道存什么数据了
2. 数组操作
1. 获取数组的长度
1. 格式: 数组名.length 2. 注意: length 后面并不要带小括号 (),因为length不是数组中的方法,而是数组中的一个属性
public class Demo02Array{ public static void main(String[] args){ String[] arr1 = {"ddd","aaa","ccc","sdsd","qwdqw"}; //定义一个变量 接受数组的长度 int len = arr1.length; System.out.println("len = " + len); } }
2. 索引
1. 概述:元素在数组中存储的位置(编号,下标) 2. 特点: a. 索引唯一,不能重复 b. 索引都是从 0 开始,因此最大索引是数组长度-1 3. 索引的作用: 我们将来操作元素,必须通过索引来操作 存数据,要指定索引 取数据,要指定索引 查数据,要指定索引
3. 存储元素
1. 格式: 数据名[索引值] = 值; -> 将等号右边的数据放到数组指定的索引位置上 arr[0] = 10;
public class Demo03Array { public static void main(String[] args) { int[] arr = new int[3]; arr[0] = 100;//将100存到了arr这个数组的0索引上 arr[1] = 200;//将200存到了arr这个数组的0索引上 arr[2] = 300;//将300存到了arr这个数组的0索引上 // arr[3] = 200;//上面的数组长度为3,最大索引是2,没有3索引,所以不能操作不存在的索引 } }
public class Demo03Array { public static void main(String[] args) { int[] arr = new int[3]; arr[0] = 100;//将100存到了arr这个数组的0索引上 arr[1] = 200;//将200存到了arr这个数组的0索引上 arr[2] = 300;//将300存到了arr这个数组的0索引上 // arr[3] = 200;//上面的数组长度为3,最大索引是2,没有3索引,所以不能操作不存在的索引 String[] arr2 = new String[3]; arr2[0] = "张三"; arr2[1] = "李四"; arr2[2] = "王五"; } }
//键盘录入数据 放到数组中 import java.util.Scanner; public class Demo04Array { public static void main(String[] args) { //键盘录入3个整数,存到数组arr里面 int[] arr = new int[3]; Scanner sc = new Scanner(System.in); // arr[0] = sc.nextInt(); // arr[1] = sc.nextInt(); // arr[2] = sc.nextInt(); // for (int i = 0; i < 3; i++) { // arr[i] = sc.nextInt(); // } // //写死了 循环三次 //优化,数组长度多少,我们就应该循环多少次 for (int i = 0; i < arr.length; i++) { arr[i] = sc.nextInt(); } System.out.println("arr = " + arr); } }
//随机数 放入数组中 public class Demo05Array { public static void main(String[] args) { int[] arr = new int[3]; Random rd = new Random(); int i = rd.nextInt(10) + 1; System.out.println("i = " + i); arr[0] = i; System.out.println("arr[0] = " + arr[0]); } }
4. 取数组元素
1. 格式: 数组名[索引值] 2. 细节说明 a. 直接输出数组名,会输出数组在内存中的地址值 b. 地址值:数组在内存中的一个身份证号,唯一标识,我们可以通过这个唯一标识,到内存中能找到这个数组,从而操作这个数组中的数据 c. 如果数组中没有存数据,那么直接获取也能获取出来一些数据(元素的默认值) 默认值: 整数:0 小数:0.0 字符:'\u0000' -> 对应的int值是 0 布尔:false 引用:null
public class Demo06Array { public static void main(String[] args) { int[] arr = new int[3]; System.out.println("arr = " + arr);//[I@682a0b20 直接输出数组名 得到的是数组的地址值 //获取数组元素 System.out.println("arr[0] = " + arr[0]); System.out.println("arr[1] = " + arr[1]); System.out.println("arr[2] = " + arr[2]); //整数默认值都是0 } }
5. 遍历数组
1. 遍历:将元素从数组中一个一个的获取出来(循环)
public class Demo06Array { public static void main(String[] args) { int[] arr = new int[3]; System.out.println("arr = " + arr);//[I@682a0b20 直接输出 数组名 得到的是数组的地址值 //获取数组元素 System.out.println("arr[0] = " + arr[0]); System.out.println("arr[1] = " + arr[1]); System.out.println("arr[2] = " + arr[2]); //整数默认值都是0 arr[0] = 100; arr[1] = 200; arr[2] = 300; System.out.println("arr[0] = " + arr[0]);//100 System.out.println("arr[1] = " + arr[1]);//200 System.out.println("arr[2] = " + arr[2]);//300 System.out.println("****************************************"); String[] arr2 = new String[3]; System.out.println("arr2 = " + arr2); System.out.println(arr2[0]);//引用数据类型默认值是null System.out.println(arr2[1]);//引用数据类型默认值是null System.out.println(arr2[2]);//引用数据类型默认值是null arr2[0] = "张无忌"; arr2[1] = "张三丰"; arr2[2] = "张翠山"; System.out.println(arr2[0]); System.out.println(arr2[1]); System.out.println(arr2[2]); System.out.println("===========遍历arr数组======================="); //数组多长,就循环多少次 for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } System.out.println("===========遍历arr2数组======================="); /* * 快捷键 * 数组名.fori * */ for (int i = 0; i < arr2.length; i++) { } } }
3. 操作数组时两个常见的问题
1. 数组索引越界异常_ArrayIndexOutOfBoundsException
1. 原因: 操作的索引超出了数组索引的范围了
2. 空指针异常_NullPointerException
1. 原因: 当一个对象为null,再调用此对象的其他成员
public class Dem09ArrayException { public static void main(String[] args) { int[] arr = new int[3]; System.out.println(arr.length); arr = null; System.out.println("arr.length = " + arr.length); } }
4. 数组练习
1. 需求:求出数组中的元素最大值 (元素和元素之间两两比较,取较 大的,一直比较,直到求出最大值) 步骤: 1. 定义一个变量max,用来接受两个元素比较之后的较大值 2. 遍历数组,将每一个元素获取出来进行比较 3. 判断,如果max小于遍历出来的元素,证明遍历出来的元素大,就将大的重新赋值给 max 4. 最后输出max,此时max为最大值 2. 随机产生10个[0,100]之间的整数,统计既是3又是5,但不是7的倍数的个数 步骤: 1. 创建Random对象,用于生成随机数 2. 定义一个数组,长度为10,用来存放生成的10个数 3. 定义一个遍历count,用于统计符合条件的数据个数 4. 遍历数组,判断元素是否符合指定的条件,如果符合,count++ 5. 输出count 3. 用一个数组存储本组学员的姓名,从键盘输入,并遍历显示 4. 需求: 1. 定义一个数组,int[] arr = {1,2,3,4}; 2. 遍历数组,输出元素按照 [1,2,3,4] 这样的格式 5. 需求:随机50个 1 - 100 之间的整数,统计偶数个数 步骤: 1. 创建Random对象 2. 定义长度为50的数组 3. 随机50个存储到数组中 4. 遍历数组,判断,如果是偶数,count++ 5. 输出count 6. 键盘录入一个整数,找出整数中存储的索引位置 步骤: 1. 创建Scanner对象 2. 定义数组,随便存几个数据 3. 遍历数组,在遍历的过程中判断是否和录入的数相等,如果相等,输出索引 4. 如果查不到,就输出-1,代表没有查到
7. 数组复制 public class Demo06Copy { public static void main(String[] args) { int[] arr1 = {1,2,3,4}; int[] arr2 = new int[4]; for (int i = 0; i < arr1.length; i++) { arr2[i] = arr1[i]; } for (int i = 0; i < arr2.length; i++) { System.out.print(arr2[i] + " "); } } 1. 如果arr[i]在等号右边,证明是获取值,如果在等号左边,证明是存值 arr[0] = 100; arr2[i] = arr1[i] -> 先看等号右边的,相当于将arr1数组的i索引上的数据, 保存到arr2数组的i索引上 arr2[0] = arr1[0] -> 先看等号右边的,将arr1的0索引上的元素取出来,保存 到arr2数组的0索引上
8. 数组扩容 需求: 定义一个数组:int[] arr1 = {1,2,3,4,5} 将数组由原来的长度扩容到10
public class Demo07Array { public static void main(String[] args) { int[] oldArr = {1,2,3,4,5}; //创建新数组 int[] newArr = new int[10]; //将老数组中的元素复制到新数组中 for (int i = 0; i < oldArr.length; i++) { newArr[i] = oldArr[i]; } //将新数组的地址值 给 老数组 oldArr = newArr; System.out.println("oldArr.length = " + oldArr.length); for (int i = 0; i < oldArr.length; i++) { System.out.println(oldArr[i]); } }
9. 数组合并 int[] arr1 = {1,2,3}; int[] arr2 = {4,5,6};
public class Demo08Array { public static void main(String[] args) { int[] arr1 = {1, 2, 3}; int[] arr2 = {4,5,6}; int[] newArr = new int[arr1.length + arr2.length]; for (int i = 0; i < arr1.length; i++) { newArr[i] = arr1[i]; } for (int i =0; i < arr2.length; i++) { newArr[arr1.length + i] = arr2[i]; } for (int i = 0; i < newArr.length; i++) { System.out.println(newArr[i]); } }
第二章. 内存图
1. 内存的划分
1. 内存: 可以理解为:"内存条",所有的软件,程序运行起来都会进入到内存中,"占用内存", 2. java中,将内存划分成了5块 a. 栈(重点)(Stack) 主要运行"方法",方法的运行都会进"栈内存"运行,运行完毕之后,需要"弹栈",为了腾空间 b. 堆(重点)(Heap) 保存的是"对象,数组",每 new 一次,都会在堆内存中开辟空间,并为这个空间分配一个"地址值",堆内存中的数据都是有"默认值"的 c. 方法区(重点)(Method Area) 代码的"预备区",记录了"类的信息以及方法的信息" 方法区中主要保存 class 文件以及其中的信息 代码运行之前,需要"先进内存(方法区)",之后,该进栈进栈,该进堆进堆 d. 本地方法栈(了解)(Native Method Stack):专门运行 native 方法(本地方法) 本地方法可以理解为堆对java功能的扩充 有很多功能,java语言实现不了,所以就需要依靠本地方法完成 (本地方法都是c语言编写) e. 寄存器(了解)(pc register) -> 和cpu有关
2. 一个数组的内存图
模板
3. 两个数组的内存图
我们创建了两个数组,在堆内存中开辟了两个不同的空间。此时修改一个空间中的数据不会影响到另外一个空间的数据
4. 两个数组指向同一片空间内存图
arr2不是new出来的,是arr1直接赋值给的,arr1在内存中保存的是地址值,给了arr2, 那么arr2的地址值和arr1一样,所以此时arr1和arr2指向了堆内存中的同一片空间,(同一个地址值,代表的是同一个数组),此时改变一个数组中的元素会影响到另外一个数组
第三章. 二维数组
1. 定义二维数组
1. 概述:数组中套了多个数组 2. 定义格式: a. 动态初始化 数据类型[][] 数组名 = new 数据类型[m][n]; 或者 数据类型 数组名[][] = new 数据类型[m][n]; 或者 数据类型[] 数组名[] = new 数据类型[m][n]; m: 代表的是二维数组的长度(二维数组中存了m个一维数组) n:代表的是二维数组中每一个一维数组的长度(每个一维数组中有n个元素) 数据类型[][] 数组名 = new 数据类型[m][]; -> 二维数组中的一维数组没有 被创建 b. 静态初始化: 数据类型[][] 数组名 = new 数据类型[][]{{元素1,元素2...},{元素1,元 素2...}...}; 或者 数据类型 数组名[][] = new 数据类型[][]{{元素1,元素2...},{元素1,元 素2...}...}; 或者 数据类型[] 数组名[] = new 数据类型[][]{{元素1,元素2...},{元素1,元 素2...}...}; 简化静态初始化: 数据类型[][] 数组名 = {{元素1,元素2...},{元素1,元素2...}...}; 或者 数据类型 数组名[][] = {{元素1,元素2...},{元素1,元素2...}...}; 或者 数据类型[] 数组名[] = {{元素1,元素2...},{元素1,元素2...}...};
public class Demo01Array { public static void main(String[] args){ int[][] arr1 = new int[2][2]; int[][] arr2 = new int[2][]; System.out.println("=========================================="); String[][] arr3 = {{"孙悟空","唐僧"},{"刘备","关羽","张飞"},{"宋江"},{"林黛玉","贾宝玉"}}; } }
使用动态初始化 每一个一维数组长度固定 使用静态初始化,每一个一维数组长度不固定
2. 二维数组操作
1. 获取长度
1. 格式: 二维数组名.length 2. 获取每一个一维数组长度,需要先遍历二维数组,将每一个一维数组遍历出来
public class Demo02Array { public static void main(String[] args) { String[][] arr1 = {{"孙悟空", "唐僧"}, {"刘备", "关羽", "张飞"}, {"宋江"}, {"林黛玉", "贾宝玉"}}; System.out.println(arr1.length); System.out.println("*************************************************"); //获取二维数组中每一个一维数组长度 遍历 for (int i = 0; i < arr1.length; i++) { // arr1[i]代表每一个一维数组 System.out.println(arr1[i].length); } }
2. 获取元素
1. 格式: 数组名[i][j] i: 代表的是一维数组在二维数组中的索引位置 j: 代表的是元素在一维数组中的索引位置
public class Demo03Array { public static void main(String[] args) { String[][] arr1 = {{"孙悟空", "唐僧"}, {"刘备", "关羽", "张飞"}, {"宋江"}, {"林黛玉", "贾宝玉"}}; System.out.println(arr1[0][0]); System.out.println(arr1[2][0]); System.out.println(arr1[3][1]); } }
3. 存储元素
1. 格式: 数组名[i][j] = 值; i: 代表的是一维数组在二维数组中的索引位置 j: 代表的是元素在一维数组中的索引位置
public class Demo04Array { public static void main(String[] args) { String[][] arr = new String[2][2]; arr[0][0] = "张飞"; arr[0][1] = "李逵"; arr[1][0] = "刘备"; arr[1][1] = "宋江"; System.out.println(arr[0][0]); System.out.println(arr[0][1]); System.out.println(arr[1][0]); System.out.println(arr[1][1]); }
4. 数组遍历
1. 先遍历二维数组,将每一个一维数组遍历出来 2. 再遍历每一个一维数组,将元素获取出来
public class Demo05Array { public static void main(String[] args) { String[][] arr = new String[2][2]; arr[0][0] = "张飞"; arr[0][1] = "李逵"; arr[1][0] = "刘备"; arr[1][1] = "宋江"; //遍历二维数组 for (int i = 0; i < arr.length; i++) { for (int j = 0; j < arr[i].length; j++) { System.out.println(arr[i][j]); } } }
5. 二维数组内存图
public class Demo06Array { public static void main(String[] args) { int[][] arr1 = new int[3][]; arr1[1] = new int[]{1,2,3}; arr1[2] = new int[3]; arr1[2][1] = 100; }