当前位置: 首页 > news >正文

Java从入门到精通 - 数组

数组

此笔记参考黑马教程,仅学习使用,如有侵权,联系必删

文章目录

  • 数组
    • 1. 认识数组
    • 2. 数组的定义和访问
      • 2.1 静态初始化数组
        • 2.1.1 数组的访问
          • 2.1.1 定义
          • 代码实现
          • 总结
        • 2.1.2 数组的遍历
          • 2.1.2.1 定义
          • 代码演示
          • 总结
        • 案例
          • 代码实现
      • 2.2 动态初始化数组
        • 2.2.1 定义
        • 2.2.2 动态初始化数组元素默认值规则
        • 代码实现
        • 总结
        • 案例
          • 代码实现
    • 3. 数组在计算机中的执行原理
      • 3.1 数组的执行原理,Java 程序的执行原理
        • 3.1.1 Java 内存分配介绍
        • 3.1.2 方法区
        • 3.1.3 栈
        • 3.1.4 堆
        • 3.1.5 数组在计算机中的执行原理
        • 总结
      • 3.2 多个变量指向同一个数组的问题
        • 3.2.1 使用数组时常见的一个问题
        • 代码实现
        • 总结
    • 专项训练:数组常见案例
      • 数组求最值
        • 分析
        • 代码实现
        • 总结
      • 数组反转
        • 需求 - 分析
        • 代码实现
        • 总结
      • 随机排名
        • 代码实现
        • 总结
    • 补充知识:Debug 工具的使用
    • 总结

1. 认识数组

  • 数组就是一个容器,用来存储一批同种类型的数据

  • 例子:

// 20, 10, 80, 60, 90
int[] arr = {20, 10, 80, 60, 90};// 张三, 李四, 王五
String[] names = {"张三", "李四", "王五"};

Java 中有变量,为什么还要用数组?

  • eg:在一组名单中随机点名的话,根据以往方法可能要定义几十上百个变量,会使得代码繁琐、实现需求复杂。而用数组的话代码简洁、逻辑清晰

  • 结论:遇到批量数据的存储和操作时,数组比变量更合适


2. 数组的定义和访问

2.1 静态初始化数组

  • 定义数组的时候直接给数组赋值

静态初始化数组的格式:

// 完整格式
数据类型[] 数组名 = new 数据类型[]{元素1, 元素2, 元素3, ...};
int[] ages = new int[]{12, 24, 36};
double[] scores = new double[]{89.9, 99.5, 59.5, 88.0};
// 简化格式
数据类型[] 数组名 = {元素1, 元素2, 元素3, ...};
int[] ages = {12, 24, 36};

注意:

  • 数据类型[] 数组名“ 也可以写成 ”数据类型 数组名[]

  • 什么类型的数组只能存放什么类型的数据

  • 数组在计算机中的基本原理

    • 在计算机遇到代码之后,现在内存中开辟一块变量空间,暂时先不装东西。元素部分又开辟一个区域,每个元素各分为一块来存储数据,而这块区域是有自己的一个地址的,每个元素都有自己的编号(索引),然后将这个地址交给数组变量来存储

注意:数组变量名中存储的是数组在内存中的地址,数组是一种引用数据类型

  • 代码演示
package e_ArrayApp;public class a_ArrayDemo1 {public static void main(String[] args) {// 目标:掌握数组的定义方式一:静态初始化数组// 1. 数据类型[] 数组名 = new 数据类型[]{元素1, 元素2, 元素3, ...};int[] ages = new int[]{12, 24, 36};double[] scores = new double[]{89.9, 99.5, 59.5, 88};System.out.println(ages);System.out.println(scores);// 2. 简化写法// 数据类型[] 数组名 = {元素1, 元素2, 元素3, ...};int[] ages2 = {12, 24, 36};double[] scores2 = {89.9, 99.5, 59.5, 88};// 3. 数据类型[] 数组名 也可以写成 数据类型 数组名[]int ages3[] = {12, 24, 36};double scores3[] = {89.9, 99.5, 59.5, 88};}
}
  • 总结
  1. 数组的静态初始化的写法和特点是什么样的?

  1. 定义数组我们说了哪几个注意点?
  • 什么类型的数组必须存放什么类型的数据
  • 数据类型[] 数组名 也可以写成 数据类型 数组名[]
  1. 数组是属于什么类型,数组变量名中存储的是什么?
  • 引用数据类型,存储的数组在内存中的地址信息

2.1.1 数组的访问
2.1.1 定义
数组名[索引]

  • 数组的长度属性:length
// 获取数组的长度(就是数组元素的个数)
System.out.println(arr.length);
  • 数组的最大索引怎么表示?
数组名.length - 1 // 前提:元素个数大于0
代码实现
package e_ArrayApp;public class b_ArrayDemo {public static void main(String[] args) {// 目标:掌握数组的访问int[] arr = {12, 24, 36};// 1. 访问数组的全部数据System.out.println(arr[0]); // 12System.out.println(arr[1]); // 24System.out.println(arr[2]); // 36// 2. 修改数组中的数据arr[0] = 66;arr[2] = 100;System.out.println(arr[0]); // 66System.out.println(arr[1]); // 24System.out.println(arr[2]); // 100// 3. 访问数组的元素个数:数组名.lengthSystem.out.println(arr.length); // 3// 技巧:获取数组的最大索引:arr.length - 1(前提是数组中存在数据)System.out.println(arr.length - 1); // 2}
}
总结
  1. 如何访问数组的元素?
数组名[索引]
  1. 如何访问数组的长度?
  • 数组名称.length
  1. 数组的最大索引是多少?
数组名.length - 1 // 前提:元素个数大于0
  1. 如果访问数组时,使用的索引超过了数组的最大索引会出什么问题?
  • 执行程序时会出 bug,出现一个索引越界的异常提示

2.1.2 数组的遍历
2.1.2.1 定义
  • 遍历:就是一个一个数据的访问
  • 数组遍历:就是把数组的每个数据都取一遍出来

快速方法:

  • 数组名.fori + Tab
代码演示
package e_arrayapp;public class c_ArrayDemo3 {public static void main(String[] args) {// 目标:掌握数组的遍历int[] ages = {12, 24, 36};// System.out.println(ages[0]); // 12// System.out.println(ages[1]); // 24// System.out.println(ages[2]); // 36for (int i = 0; i < ages.length; i++) {// i = 0 1 2System.out.println(ages[i]); // 12 24 36}}
}
总结
  1. 什么是遍历?
  • 一个一个的访问一遍容器中的数据
  1. 如何遍历数组?
int[] ages = {20, 30, 40, 50};
for (int i = 0; i < ages.length; i++) {// i = 0 1 2System.out.println(ages[i]); // 12 24 36
}

案例

需求:

  • 某部门5名员工的销售额分别是:16、26、36、6、100,请计算出他们部门的总销售额
  • 分析:
  1. 把这5个数据拿到程序中去 —> 使用数组
int[] money = {16, 26, 36, 6, 100};
  1. 遍历数组中的每一个数据,然后在外面定义求和变量把他们累加起来
代码实现
package e_arrayapp;public class d_ArrayTest4 {public static void main(String[] args) {// 目标:完成对数据的元素求和// 1. 定义一个数组存储5名员工的销售额int[] money = { 16, 26, 36, 6, 100 };// 3. 定义一个变量用于累加求和int count = 0;// 2. 遍历这个数组中的每个数据for (int i = 0; i < money.length; i++) {// i = 0 1 2 3 4count += money[i];}System.out.println("员工的销售额:" + count); // 184}
}

2.2 动态初始化数组

2.2.1 定义

数组的动态初始化:

  • 定义数组时先不存入具体的元素值,只确定数组存储的数据类型和数组的长度

数组的动态初始化格式:

数据类型[] 数组名 = new 数据类型[长度];
int[] arr = new int[3];
// 后赋值
arr[0] = 10;
System.out.println(arr[0]); // 10

  • 在内存中分配一个变量空间,在这个变量里面存储的还是数组对象的地址,这个数组对象里面,一开始会存一些所谓的默认值,后期再往这个里面进行赋值

注意:

  • 静态初始化和动态初始化数组的写法是独立的,不可以混用
2.2.2 动态初始化数组元素默认值规则
数据类型明细默认值
基本类型byte、short、char、int、long0
float、double0.0
booleanfalse
引用类型类、接口、数组、Stringnull
代码实现
package e_arrayapp;public class e_ArrayDemo5 {public static void main(String[] args) {// 目标:掌握定义数组的方式二:动态初始化数组// 1. 数据类型[] 数组名 = new 数据类型[长度];int[] ages = new int[3]; // ages = [0, 0, 0]System.out.println(ages[0]); // 0System.out.println(ages[1]); // 0System.out.println(ages[2]); // 0ages[0] = 12;ages[1] = 18;ages[2] = 32;System.out.println(ages[0]); // 12System.out.println(ages[1]); // 18System.out.println(ages[2]); // 32System.out.println("------------------------");char[] chars = new char[3]; // [0, 0, 0]System.out.println((int) chars[0]); // 0System.out.println((int) chars[2]); // 0double[] scores = new double[80];System.out.println(scores[0]); // 0.0System.out.println(scores[79]); // 0.0boolean[] flags = new boolean[100];System.out.println(flags[0]); // falseSystem.out.println(flags[99]); // falseString[] names = new String[80];System.out.println(names[0]); // nullSystem.out.println(names[79]); // null}
}
总结
  1. 动态数组的写法是什么样的?有什么特点?
数据类型[] 数组名 = new 数据类型[长度];
int[] ages = new int[4];
  1. 动态初始化数组后元素的默认值是什么样的?
  • byte、short、int、char、long 类型数组的元素默认值都是0
  • float、double 类型数组元素的默认值都是0.0
  • boolean 类型数组的元素默认值是 false,String 类型数组的元素的默认值是 null
  1. 两种数组定义的方法各自适合什么业务场景?
  • 动态初始化:适合开始不确定具体元素值,只知道元素个数的业务场景
  • 静态初始化:适合一开始就知道要存入哪些元素值的业务场景

案例

需求:

  • 某歌唱比赛,需要开发一个系统:可以录入6名评委的打分,录入完毕后立即输出平均分做为选手得分
  • 分析:
  1. 6名评委的打分是后期录入的,一开始不知道具体的分数,因此定义一个动态初始化的数组存分数
double[] scores = new double[6];
  1. 遍历数组中的每个位置,每次提示用户录入一个评委的分数,并存入数组对应的位置
  2. 遍历数组中的每一个元素进行求和最终算出平均分打印出来即可
代码实现
package e_arrayapp;import java.util.Scanner;public class f_ArrayTest6 {public static void main(String[] args) {// 目标:完成评委打分的案例// 1. 定义一个动态初始化的数组,负责存储6个评委的打分double[] scores = new double[6];Scanner sc = new Scanner(System.in);// 2. 遍历数组中的每个位置,录入评委的分数,存入数组中去for (int i = 0; i < scores.length; i++) {// i = 0 1 2 3 4 5 6System.out.println("请您输入当前第" + (i + 1) + "评委的分数");double score = sc.nextDouble();scores[i] = score;}// 3. 遍历数组中的每个元素进行求和double sum = 0;for (int i = 0; i < scores.length; i++) {sum += scores[i];}System.out.println("选手最终得分是:" + sum / scores.length);}
}

3. 数组在计算机中的执行原理

3.1 数组的执行原理,Java 程序的执行原理

前面我们知道,程序都是在计算机中的内存中执行的,那么 Java 程序编译后会产生一个 class 文件,然后这个 class 文件是提取到内存中正在运行的虚拟机里面去执行的。那么 Java 为了便于虚拟机执行这个 Java 程序,它将虚拟机中的这块内存区域进行了划分

3.1.1 Java 内存分配介绍
  • 方法区
  • 本地方法栈
  • 程序计数器
3.1.2 方法区
  • 定义:放我们编译以后的 class 文件的,也就是字节码文件

3.1.3 栈
  • 定义:方法运行时所进入的内存,由于变量是在方法里面的,所以变量也在这块区域里

3.1.4 堆
  • 定义:堆里面放的都是 new 出来的东西,它会在这块堆内存中开辟空间并产生地址,比如之前用的数组就是放在队里面的

ps:堆和栈在数据结构中应用广泛,具体可见 数据结构与算法

3.1.5 数组在计算机中的执行原理

把程序的 class 文件提取到方法区里面来,这里面会有一个 main 方法。接着它会把这个 main 方法加载到我们的栈里面来执行,接着它就会正式执行 main 方法的第一行代码,代码中基本类型变量就会在栈里面开辟空间。如果执行创建数组,就会先在栈里面开辟一个变量空间,一开始变量里面并没有存数据,紧接着执行等号右边的代码(new 一个数组对象),在堆内存中开辟一块空间,这块空间会分成 n 块等分的区域每个元素也有自己的索引,并且也会有一个地址,然后把这个地址赋值给左边的这个变量,再由变量指向这个数组对象

总结
  1. 运行一个 Java 程序,主要看 JVM 中包含的哪几部分内存区域?
  • 方法区
  • 栈内存
  • 堆内存
  1. 简单说说 int a = 20; int[] arr = new int[3] 这两行代码的执行原理?
  • a 是变量,直接放在栈中,a 变量存储的数据就是20这个值
  • new int[3] 是创建一个数组对象,会在堆内存中开辟区域存储3个整数
  • arr 是变量,在栈中,arr 中存储的是数组对象在堆内存中的地址值

3.2 多个变量指向同一个数组的问题

3.2.1 使用数组时常见的一个问题
  • 如果某个数组变量存储的地址是 null,那么该变量将不再指向任何数组对象

arr2 = null; // 把null赋值给arr2System.out.println(arr2); // nullSystem.out.println(arr2[0]); // 会出异常
System.out.println(arr2.length); // 会出异常
代码实现
package f_memory;public class b_ArrayDemo2 {public static void main(String[] args) {// 目标:认识多个变量指向同一个数组对象的形式,并掌握其注意事项int[] arr1 = {11, 22, 33};// 把int类型的数组变量arr1赋值给int类型的数组变量arr2int[] arr2 = arr1;System.out.println(arr1); // [I@5caf905dSystem.out.println(arr2); // [I@5caf905darr2[1] = 99;System.out.println(arr1[1]); // 99arr2 = null; // 拿到的数组变量中存储的值是nullSystem.out.println(arr2);// System.out.println(arr2[0]);System.out.println(arr2.length);}
}
总结
  1. 多个数组变量,指向同一个数组对象的原因是什么?需要注意什么?
  • 多个数组变量中存储的是同一个数组对象的地址
  • 多个变量修改的都是同一个数组对象中的数据
  1. 如果某个数组变量中存储的 null,代表什么意思?需要注意什么?
  • 代表这个数组变量没有指向数组对象
  • 可以输出这个变量,但不能用这个数组变量去访问数据或者访问数组长度,会报空指针异常:NullPointerException

专项训练:数组常见案例

数组求最值

分析

实现步骤:

  • 把数据拿到程序中去,用数组装起来
int[] socres = {15, 9000, 10000, 20000, 9500, -5};
  • 定义一个变量用于记录最终的最大值
int[] max = socres[0]; // 建议存储数组的第一个元素值作为参照 
  • 从第二个位置开始:遍历数组的数据,如果遍历的当前数据大于 max 变量存储的数据,则替换变量存储的数据为当前数据
  • 循环结束后输出 max 变量即可
代码实现
package g_demo;public class a_Test1 {public static void main(String[] args) {// 目标:掌握数组元素求最值// 1. 把数据拿到程序中来,用数组装起来int[] scores = {15, 9000, 10000, 20000, 9500, -5};// 2. 定义一个变量用于最终记住最大值int max = scores[0];// 3. 从数组的第二个位置开始遍历for (int i = 0; i < scores.length; i++) {// i = 1 2 3 4 5// 判断一个当前遍历的这个数据,是否大于最大值变量max存储的数据,如果大于当前遍历的数据需要赋值给maxif (scores[i] > max) {max = scores[i];}}System.out.println("最大数据是:" + max); // 20000}
}
总结
  1. 求数组中的元素最大值,我们是如何实现的?
  • 把数据拿到程序中去,用数组装起来
  • 定义一个变量 max 用于记录最大值,max 变量默认存储了第一个元素值作为参照物
  • 从第二个位置开始遍历数组的数据,如果当前元素大于变量存储的数据,则替换变量存储的值为该元素
  • 循环结束后输出 max 变量即可

数组反转

需求 - 分析

需求:

  • 某个数组有5个数据:10,20,30,40,50,请将这个数组中的数据进行反转
    [10, 20, 30, 40, 50] 反转后 [50, 40, 30, 20, 10]

分析:

  • 数组的反转操作实际上就是:依次前后交换数据即可实现

代码实现
package g_demo;public class b_Test2 {public static void main(String[] args) {// 目标:完成数组反转// 1. 准备一个数组int[] arr = {10, 20, 30, 40, 50};// 2. 定义一个循环,设计2个变量,一个在前,一个在后for (int i = 0, j = arr.length - 1; i < j; i++, j--) {// arr[i]   arr[j]// 交换// 1. 定义一个临时变量记住后一个位置处的值int temp = arr[j];// 2. 把前一个位置处的值赋值给后一个位置arr[j] = arr[i];// 3. 把临时变量中记住的后一个位置处的值赋值给前一个位置arr[i] = temp;}// 3. 遍历数组中的每个数据,看是否反转成功了for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " "); // 50 40 30 20 10 }}
}
总结
  1. 我们如何完成数组的反转的?
  • 使用 for 循环,控制让数组的前后位置的元素,依次交换
  1. 数组如何实现前后元素交换的?
  • 定义一个临时变量记住后一个位置处的元素值
  • 再把前一个位置处的元素,赋值给后一个位置处
  • 最后把临时变量记住的后一个位置的值赋值给前一个位置处

随机排名

需求:

  • 某公司的开发部门有5名开发人员,要进行项目进展汇报演讲,现在采取随机排名后进行汇报。请依次录入5名员工的工号,然后展示出一组随机的排名顺序

测试用例:[22, 33, 35, 13, 88] —> [13, 35, 88, 33, 22]

分析:

  • 在程序中录入5名员工的工号存储起来 —> 使用动态初始化数组的方式
  • 依次遍历数组中的每个数据
  • 每遍历到一个数据,都随机一个索引值出来,让当前数据与该索引位置处的数据进行交换
代码实现
package g_demo;import java.util.Random;
import java.util.Scanner;public class c_Test3 {public static void main(String[] args) {// 目标:完成随机排名// 1. 定义一个动态初始化的数组用于存储5名员工的工号int[] codes = new int[5];// [0, 0, 0, 0, 0]//  0  1  2  3  4// 2. 提示用户录入5名员工的工号Scanner sc = new Scanner(System.in);for (int i = 0; i < codes.length; i++) {// i = 0 1 2 3 4System.out.println("请您输入当前第" + (i + 1) + "员工的工号");int code = sc.nextInt();codes[i] = code;}// 3. 打乱数组中的元素排序Random r = new Random();for (int i = 0; i < codes.length; i++) {// codes[i]// 每遍历到一个数据,都随机一个数组索引范围内的值,然后让当前遍历的数据与索引位置处的值交换int index = r.nextInt(codes.length); // 0 - 4// 定义一个临时变量记住index位置处的值int temp = codes[index];// 把i位置处的值赋值给index位置处codes[index] = codes[i];// 把index位置原来的值赋值给i位置处codes[i] = temp;}// 4. 遍历数组中的工号输出即可for (int i = 0; i < codes.length; i++) {System.out.print(codes[i] + " ");}}
}
总结
  1. 我们是如何实现随即排名的?
  • 定义一个动态初始化的数组用于录入员工的工号
  • 遍历数组中的每个元素
  • 每遍历到一个数据,都随机一个索引值出来,让当前数据与索引位置出的数据进行交换

补充知识:Debug 工具的使用

  • IDEA(大部分 IDE 都有)自带的断点调试工具,可以控制代码从断点一行一行的执行,然后详细观看程序执行的情况

DEBUG 工具基本使用步骤

  1. 在需要控制的代码左侧,点击一下,形成断点
  2. 选择使用 DEBUG 方式启动程序,启动后程序会在断点暂停
  3. 控制代码一行一行的往下执行

断点:

用 Debug:

点击按钮,实现不同效果:


总结


相关文章:

  • RabbitMQ学习(第三天)
  • redis数据结构-08(SINTER、SUNION、SDIFF、SISMEMBER)
  • Python-UV多环境管理
  • 作业...
  • CentOS7离线安装Mysql8
  • 菜鸟之路day31一一MySQL之多表设计
  • idea中的vcs不见了,如何解决
  • 部署Superset BI(五)连接oracle数据库失败
  • LlamaIndex 第七篇 结构化数据提取
  • 进程(沉淀中)
  • ElasticSearch进阶
  • 大数据模型的构建与优化
  • 找银子 题解(c++)
  • C++ 核心基础:数字、数组、字符串、指针与引用详解
  • springboot3+vue3融合项目实战-大事件文章管理系统-更新用户密码
  • TypeScript 装饰器详解
  • Kotlin Multiplatform--03:项目实战
  • 六大设计原则
  • 2025低空经济发展趋势
  • css背景相关
  • 来沪一个月几乎未花住宿钱,女子虚构卫生问题屡薅酒店羊毛被刑拘
  • 《克莱默夫妇》导演罗伯特·本顿去世,终年92岁
  • 微软宣布将裁员3%
  • 美国4月CPI同比上涨2.3%低于预期,为2021年2月来最小涨幅
  • 第十届影像上海博览会落幕后,留给中国摄影收藏的三个问题
  • 小米SU7 Ultra风波升级:数百名车主要求退车,车主喊话雷军“保持真诚”