数 组

概述

数组是一个引用类型,是一种容器。

数组存储多个相同数据类型的数据,允许自动类型转换。例如 int 类型的数组,可以存放 byte、short 和 int 类型的数据,double 类型的数组,可以存放 byte、short、int、long、float 和 double 类型的数据。

程序示例:

public class array1 {public static void main(String[] args) {double[] hens = {1, 2, 3};   // 定义数组// 数组名为 hens,数组的类型为 double[],数组中的元素的类型为 double// 遍历数组for (int i = 0; i < hens.length; i++) {System.out.println(hens[i]);}}
}

获取数组元素个数:数组名.length

数组名是一个地址。

程序示例:

public static void main(String[] args) {double[] double1 = {1.1, 2.2, 3, 4, 5};System.out.println(double1);            // [D@119d7047float[] float1 = {1.1F, 2.2F, 3, 4, 5};System.out.println(float1);             // [F@776ec8dflong[] long1 = {1, 2, 3};System.out.println(long1);              // [J@4eec7777int[] int1 = {1, 2, 3};System.out.println(int1);               // [I@3b07d329short[] short1 = {1, 2, 3};System.out.println(short1);             // [S@41629346byte[] byte1 = {1, 2, 3};System.out.println(byte1);              // [B@404b9385boolean[] boolean1 = {false, false, true, false, true};System.out.println(boolean1);           // [Z@6d311334char[] char1 = {'1', '2', '3'};System.out.println(char1);              // 123String[] String1 = {"Hello", "World"};System.out.println(String1);            // [Ljava.lang.String;@682a0b20
}

结果前面的字母指出了数组元素的类型。结果最前面的 [ 表示是一个数组。@ 后面的内容才是真正的地址值,是一个十六进制的值。平时习惯性地将整个结果称为地址,但实际上只有 @ 后面的才是真正的地址。@ 表示一个间隔符号,是固定格式,没有什么特殊含义。

对于字符数组:

public static void main(String[] args) {char[] char1 = {'1', '2', '3'};System.out.println(char1);              // 123char[] char2 = {'1', '2', '3', '9'};System.out.println(char2);              // 1239char[] char3 = {'9', '8', '7'};System.out.println(char3);              // 987
}

数组的静态初始化

数组的初始化:在内存中,为数组容器开辟空间,并将数据存入容器中的过程。

数组初始化有两种方式:动态初始化和静态初始化。

语法:

// 完整格式:
数据类型[] 数组名 = new 数据类型[] {元素1, 元素2, ... , 元素n};
// 或者:
数据类型 数组名[] = new 数据类型[] {元素1, 元素2, ... , 元素n};

例如:

int[] arr1 = new int[]{1, 2, 3};
double[] arr2 = new double[]{1.1, 2.2, 3.3};
// 简化格式:
数据类型[] 数组名 = {元素1, 元素2, ... , 元素n};
// 或者:
数据类型 数组名[] = {元素1, 元素2, ... , 元素n};

例如:

int[] a = {1, 2, 3};   // 等价于 int a[] = {1, 2, 3};

程序示例:

public class ArrayDemo {public static void main(String[] args) {// 需求1:定义数组存储5个学生的年龄int[] arr1 = new int[]{12, 14, 16, 17, 18};int[] arr2 = {12, 14, 16, 17, 18};// 需求2:定义数组存储3个学生的姓名String[] arr3 = new String[]{"zhangsan", "lisi", "wangwu"};String[] arr4 = {"zhangsan", "lisi", "wangwu"};// 需求3:定义数组存储4个学生的身高double[] arr5 = new double[]{1.9, 1.8, 1.7, 1.6};double[] arr6 = {1.9, 1.8, 1.7, 1.6};}
}

程序示例:

// 定义一个数组,存储 1,2,3,4,5
// 遍历数组得到每一个元素,求数组里面所有的数据和
public class array1 {public static void main(String[] args) {int[] nums = {1, 2, 3, 4, 5};int sum = 0;for (int i = 0; i < nums.length; i++) {sum += nums[i];}System.out.println(sum);    // 15}
}

程序示例:

// 定义一个数组
// 存储 1,2,3,4,5,6,7,8,9,10
// 遍历数组得到每一个元素,统计数组里面一共有多少个能被 3 整除的数字public class array1 {public static void main(String[] args) {int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};int count = 0;for (int i = 0; i < nums.length; i++) {if (nums[i] % 3 == 0)++count;}System.out.println("数组中能被3整除的数字有" + count + "个。");}
}

执行结果:

数组中能被3整除的数字有3个。

程序示例:

// 定义一个数组,存储 1,2,3,4,5,6,7,8,9,10
// 遍历数组得到每一个元素。
// 要求:
// 1、如果是奇数,则将当前数字扩大两倍
// 2、如果是偶数,则将当前数字变成二分之一public class array1 {public static void main(String[] args) {int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};System.out.println("原始数组为:");for (int i = 0; i < nums.length; i++) {System.out.print(nums[i] + "\t");}// 处理数组for (int i = 0; i < nums.length; i++) {if (nums[i] % 2 == 0)nums[i] /= 2;else nums[i] *= 2;}System.out.println("\n处理之后的数组为:");for (int i = 0; i < nums.length; i++) {System.out.print(nums[i] + "\t");}}
}

执行结果:

原始数组为:
1        2        3        4        5        6        7        8        9        10        
处理之后的数组为:
2        1        6        2        10        3        14        4        18        5

程序示例:

// 需求:已知数组元素为 {33, 5, 22, 44, 55}
// 请找出数组中最大值并打印在控制台public class array1 {public static void main(String[] args) {int[] nums = {33, 5, 22, 44, 55};int max = nums[0];for (int i = 0; i < nums.length; i++) {max = (max > nums[i] ? max : nums[i]);}System.out.println("最大值为" + max);}
}

执行结果:

最大值为55

程序示例:

// 冒泡排序
public class array1 {public static void main(String[] args) {int[] nums = {33, 5, 22, 44, 55};for (int i = 1; i <= nums.length - 1; i++) {for (int j = 0; j <= nums.length - 1 - i; j++) {if (nums[j] < nums[j + 1]) {int tmp = nums[j];nums[j] = nums[j + 1];nums[j + 1] = tmp;}}}System.out.println("从大到小进行排序:");for (int i = 0; i < nums.length; i++) {System.out.print(nums[i] + "\t");}}
}

执行结果:

从大到小进行排序:
55        44        33        22        5

程序示例:

// 需求:生成 10 个 1~100 之间的随机数存入数组。
// 1) 求出所有数据的和
// 2) 求所有数据的平均数
// 3) 统计有多少个数据比平均值小import java.util.Random;public class array1 {public static void main(String[] args) {Random r = new Random();int[] nums = new int[10];// 打印数组初始值System.out.println("数组初始值:");for (int i = 0; i < nums.length; i++) {System.out.print(nums[i] + "\t");}// 生成数组的值for (int i = 0; i < nums.length; i++) {nums[i] = r.nextInt(100) + 1;}// 打印数组现在的值System.out.println("\n数组现在的值:");for (int i = 0; i < nums.length; i++) {System.out.print(nums[i] + "\t");}// 求数组元素之和int sum = 0;for (int i = 0; i < nums.length; i++) {sum += nums[i];}// 求数组元素平均数int avg = sum / nums.length;// 求数组值小于平均数的个数int count = 0;for (int i = 0; i < nums.length; i++) {if (nums[i] < avg)++count;}System.out.println("\n数组元素之和为" + sum);System.out.println("数组元素平均值为" + avg);System.out.println("数组中元素小于平均值的个数有" + count + "个");}
}

执行结果:

数组初始值:
0        0        0        0        0        0        0        0        0        0        
数组现在的值:
72        6        35        98        45        85        16        100        85        47        
数组元素之和为589
数组元素平均值为58
数组中元素小于平均值的个数有5个

程序示例:

// 需求:定义一个数组,存入 1, 2, 3, 4, 5。按照要求交换索引对应的元素。
// 交换前:1, 2, 3, 4, 5
// 交换后:5, 2, 3, 4, 1public class array1 {public static void main(String[] args) {int[] nums = {1, 2, 3, 4, 5};System.out.println("交换之前的数组:");for (int i = 0; i < nums.length; i++) {System.out.print(nums[i] + "\t");}// 交换// int i = 0, j = nums.length - 1;// while (i <= j) {//     int tmp = nums[i];//     nums[i] = nums[j];//     nums[j] = tmp;//     ++i;//     --j;// }for (int i = 0, j = nums.length - 1; i <= j; ++i, --j) {int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}System.out.println("\n交换之后的数组:");for (int k = 0; k < nums.length; k++) {System.out.print(nums[k] + "\t");}}
}

执行结果:

交换之前的数组:
1        2        3        4        5        
交换之后的数组:
5        4        3        2        1

程序示例:

// 需求:定义一个数组,存入 1~9。要求随机打乱数组中所有数据的顺序。import java.util.Random;public class array1 {public static void main(String[] args) {int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9};System.out.println("初始状态的数组:");for (int i = 0; i < nums.length; i++) {System.out.print(nums[i] + "\t");}Random r = new Random();// 每一次遍历到当前数组元素时,只和后面的随机一个元素进行交换for (int i = 0; i < nums.length - 1; i++) {int randomIndex = r.nextInt(nums.length - 1 - i - 1 + 1) + i + 1;int tmp = nums[i];nums[i] = nums[randomIndex];nums[randomIndex] = tmp;}System.out.println("\n方法一打乱之后的数组:");for (int i = 0; i < nums.length; i++) {System.out.print(nums[i] + "\t");}// 每一次遍历到当前数组元素时,和一个随机元素进行交换for (int i = 0; i < nums.length - 1; i++) {int randomIndex = r.nextInt(nums.length);int tmp = nums[i];nums[i] = nums[randomIndex];nums[randomIndex] = tmp;}System.out.println("\n方法二打乱之后的数组:");for (int i = 0; i < nums.length; i++) {System.out.print(nums[i] + "\t");}}
}

执行结果:

初始状态的数组:
1        2        3        4        5        6        7        8        9        
方法一打乱之后的数组:
9        8        6        2        4        5        1        7        3        
方法二打乱之后的数组:
3        1        9        8        7        4        5        6        2

数组动态或者静态初始化时,允许自动类型转换,能进行自动类型转换的类型可以被赋值给数组元素,不能进行自动类型转换的类型不能赋值给数组元素,否则报错:不兼容的类型。

程序示例:

public class array1 {public static void main(String[] args) {double[] nums = {1.1, 2.2, 3, 4, 5};    // 此处的静态初始化,利用了自动类型转换for (int i = 0; i < nums.length; i++) {System.out.print(nums[i] + "\t");}}
}

执行结果:

1.1        2.2        3.0        4.0        5.0

IDEA 提供了一个快速生成数组遍历的方式:数组名.fori

[图片]

[图片]

数组中的数据类型,可以是基本类型或者引用类型。

数组下标越界会报错。编译时不检查是否越界,运行时才报错。

程序示例:

public class array1 {public static void main(String[] args) {int[] nums = {1, 2, 3};System.out.println(nums[3]);  // ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3}
}

数组的动态初始化 1

动态初始化:初始化时只指定数组的长度,由虚拟机为数组分配初始值。

动态初始化的数组的定义:

数据类型 数组名[] = new 数据类型[数组长度];
// 或者:
数据类型[] 数组名 = new 数据类型[数组长度];  // 两者等价,但是推荐使用这一种

不同数据类型的数组,默认的初始值不同。

int 类型默认初始值为 0
short 类型默认初始值为 0
byte 类型默认初始值为 0
long 类型默认初始值为 0
float 类型默认初始值为 0.0
double 类型默认初始值为 0.0
char 类型默认初始值为 \u0000 (零字符),打印出来就是一个空格。
boolean 类型默认初始值为 false
引用数据类型默认初始值为 NULL

程序示例:

public class array1 {public static void main(String[] args) {double[] hens = new double[3]; // 定义数组int[] kens = new int[4];double sumHens = 0;int sunKens = 0;// 遍历数组for (int i = 0; i < hens.length; i++) {System.out.print(hens[i] + "\t");sumHens += hens[i];}System.out.println("");for (int i = 0; i < kens.length; i++) {System.out.print(kens[i] + "\t");sunKens += kens[i];}System.out.println();System.out.println(sumHens);System.out.println(sunKens);}
}

结果:

0.0        0.0        0.0        
0        0        0        0        
0.0
0

程序示例:

public class array1 {public static void main(String[] args) {byte[] bytes = new byte[10];short[] shorts = new short[10];int[] ints = new int[10];long[] longs = new long[10];char[] chars = new char[10];boolean[] booleans = new boolean[10];float[] floats = new float[10];double[] doubles = new double[10];String[] Strings = new String[10];System.out.println(bytes[0]);           // 0System.out.println(shorts[0]);          // 0System.out.println(ints[0]);            // 0System.out.println(longs[0]);           // 0System.out.println(chars[0]);System.out.println(booleans[0]);        // falseSystem.out.println(floats[0]);          // 0.0System.out.println(doubles[0]);         // 0.0System.out.println(Strings[0]);         // null}
}

执行结果:

0
0
0
0false
0.0
0.0
null

程序示例:

// 空字符 \u0000 打印出来就是一个空格
public class array1 {public static void main(String[] args) {System.out.println("Hello\u0000World!");    // Hello World!}
}

数组的动态初始化 2

先声明数组,语法:

数据类型 数组名[];
// 或者:
数据类型[] 数组名;

再创建数组,语法:

数组名 = new 数据类型[数组长度];

例如:

int[] a;           // 或者 int a[];   此时还没有在内存中为 a 分配空间,a 是 NULL
a = new int[10];   // 此时在内存中为 a 分配了空间,只有分配了存储空间,才能存放数据,否则报错,显示空指针异常

其实就是把方式 1 分两步写了。

错误代码:

// 在未分配空间的情况下,访问数组的长度:
public class array1 {public static void main(String[] args) {double[] a;System.out.println(a.length);  // 可能尚未初始化变量 a}
}

数组赋值

数组赋值是引用传递,传递的是地址。

程序示例:

public class ArrayAssign {public static void main(String[] args) {int[] arr1 = {1, 2, 3};int[] arr2 = arr1;for (int i = 0; i < arr1.length; i++) {System.out.print(arr1[i] + " ");}System.out.println("");arr2[1] = 100;for (int i = 0; i < arr1.length; i++) {  // 修改 arr2 会影响 arr1System.out.print(arr1[i] + " ");}}
}

执行结果:

1 2 3 
1 100 3 

程序示例:

public class test {public static void main(String[] args) {// 给定一个初始数组int[] arr1 = {1, 2, 3};// 遍历打印初始数组for (int i = 0; i < arr1.length; i++) {System.out.print(arr1[i] + " ");}// 调用方法修改数组change(arr1);// 遍历打印修改后的数组System.out.println();for (int i = 0; i < arr1.length; i++) {System.out.print(arr1[i] + " ");}}// 修改数组的方法public static void change(int[] arr) {arr[0] = 100;}
}

执行结果:

1 2 3 
100 2 3 

JVM 内存

在这里插入图片描述

在 JDK 7 之前,JVM 将方法区和堆放在一起,在真实的物理内存中,也是一块连续的空间。但是这种设计方式不太好。从 JDK 8 开始,取消方法区,新增元空间。把原来方法区的多种功能进行拆分,有的功能放到了堆中,有的功能放到了元空间中。

寄存器:给 CPU 使用,和我们开发无关。

本地方法栈:JVM 在使用操作系统功能的时候使用,和我们开发无关。

栈:方法运行时使用的内存,比如 main 方法运行时会先进栈。基本数据类型都放在栈中。

堆:存储对象或者数组,只要是 new 出来的东西,比如数组,都存储在堆内存。new 出来的东西会在堆内存中开辟空间并产生地址,表示在堆内存中的位置。

方法区:存储可以运行的 class 文件。当一个类要运行时,要把这个类的字节码文件,即 class 文件加载到方法区中临时存储。

[图片]

数组的静态初始化可以有简化的书写方式,这种书写方式是没有 new 关键字的,但是还是认为是有 new 关键字的,只是省略没写,所以还是 new 出来的东西。

[图片]

[图片]

[图片]

[图片]

[图片]

int[] arr1 中的 int[] 表示 arr1 可以存放 int 型数组的地址。

当两个数组指向同一个小空间时,其中一个数组对小空间中的值发生了改变,那么其他数组再次访问的时候都是修改之后的结果了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/350961.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Apache Doris】周FAQ集锦:第 5 期

【Apache Doris】周FAQ集锦&#xff1a;第 5 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目&#xff01; 在这个栏目中&#xff0c;每周将筛选社区反馈的热门问题和话题&#xff0c;重点回答并进行深入探讨。旨在为广大用户和…

zip加密txt文件后,暴力破解时会有多个解密密码可以打开的疑问??

最近在做一个关于zip压缩文件解密的测试&#xff0c;发现通过暴力解密时&#xff0c;会有多个解密密码可以打开&#xff0c;非常疑惑&#xff0c;这里做个问题&#xff0c;希望能有大佬解惑。 1、首先在本地创建一个113449.txt的文件&#xff0c;然后右键txt文件选择压缩&…

1586. 扫地机器人

问题描述 Mike同学在为扫地机器人设计一个在矩形区域中行走的算法,Mike是这样设计的:先把机器人放在出发点 (1,1)(1,1) 点上,机器人在每个点上都会沿用如下的规则来判断下一个该去的点是哪里。规则:优先向右,如果向右不能走(比如:右侧出了矩形或者右侧扫过了)则尝试向…

为什么说Python 是胶水语言?

​ "Python 是胶水语言"这一说法是指它很擅长将不同的程序或代码库连接在一起&#xff0c;能够让来自不同编程语言或框架的组件无缝协作。Python 具有丰富的库和简单的语法&#xff0c;使得它可以轻松调用其他语言编写的程序或使用不同技术栈的模块。 ​ 以下是几个…

Linux C编译器从零开发二

自定义分词器 test.c #include <ctype.h> #include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h>typedef enum {TK_PUNCT, // PunctuatorsTK_NUM, // Numeric literalsTK_EOF, // …

线上教育培训办公系统系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;教师管理&#xff0c;学生管理&#xff0c;运营事件管理 教师账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;作业管理&#xff0c;电…

用CloudCompare软件拟合点云中的圆柱体

用CloudCompare软件拟合点云中的圆柱体 软件下载 点击下面的链接&#xff0c;进入下载页面&#xff1a; 下载页面 然后根据需要选择下载合适的软件版本。 一般选择windows installer版&#xff0c;如图所示&#xff1a; 下载完成后&#xff0c;安装并打开软件。软件的默认语…

【MySQL】在CentOS环境下安装MySQL

目录 一、卸载残留环境 二、获取官方yum源 三、安装yum源 四、安装MySQL 五、启动MySQL 一、卸载残留环境 输入 ps axj | grep mysql 查看是否存在正在运行的MySQL服务 如果有&#xff0c;则先输入 systemctl stop mysqld 来关闭服务 然后输入 rpm -qa | grep mysql 查看…

XGBoost预测及调参过程(+变量重要性)--血友病计数数据

所使用的数据是血友病数据&#xff0c;如有需要&#xff0c;可在主页资源处获取&#xff0c;数据信息如下&#xff1a; 读取数据及数据集区分 数据预处理及区分数据集代码如下&#xff08;详细预处理说明见上篇文章--随机森林&#xff09;&#xff1a; import pandas as pd im…

SQLServer 借助Navcate做定时备份的脚本

首先创建SQLServer链接&#xff0c;然后在Query标签种创建一个查询 查询内容如下 use ChengYuMES declare ls_time varchar(1000) declare ls_dbname varchar(1000) set ls_time convert(varchar, getdate(), 112) _ replace(convert(varchar, getdate(), 108), :, )-- 需…

68. UE5 RPG 优化敌人角色的表现效果

我们现在已经有了四个敌人角色&#xff0c;接下来&#xff0c;处理一下在战斗中遇到的问题。 处理角色死亡后还会攻击的问题 因为我们有角色溶解的效果&#xff0c;角色在死亡以后的5秒钟才会被销毁掉。所以在这五秒钟之内&#xff0c;角色其实还是会攻击。主要时因为AI行为树…

LeetCode 算法:回文链表 c++

原题链接&#x1f517;&#xff1a;回文链表 难度&#xff1a;简单⭐️ 题目 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head…

C++11移动语义

前言 之前我们已经知道了在类里开辟数组后&#xff0c;每一次传值返回和拷贝是&#xff0c;都会生成一个临时变量 class Arr { public://构造Arr() {/*具体实现*/ };//拷贝Arr(const Arr& ar) {/*具体实现*/ };//重载Arr operator(const Arr& ar) { /*具体实现*/Arr …

Python高级编程:Functools模块的8个高级用法,强烈建议添加到你的开发工具箱中!

目录 1. functools.partial 2. functools.lru_cache lru_cache的特点 cache的特点 性能比较与选择 3. functools.reduce functools.reduce的作用 工作原理 示例 累加序列中的所有元素 计算阶乘 initializer的使用 应用场景 示例:计算平均销售额 小结 4. funct…

微前端乾坤方案

微前端乾坤方案 了解乾坤 官方文档 介绍 qiankun 是一个基于 single-spa 的微前端实现库&#xff0c;旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。 qiankun 的核心设计理念 &#x1f944; 简单 由于主应用微应用都能做到技术栈无关&#xff0c;qiankun 对…

Java 桥接模式(Bridge Pattern)是设计模式中的一种结构型设计模式,桥接模式的核心思想是将抽象与实现解耦

桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;它将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。桥接模式的核心思想是将抽象与实现解耦&#xff0c;使得它们可以独立扩展。 在桥接模式中&#xff0c;通常包含以下四个…

DAY3-力扣刷题

1.罗马数字转整数 13. 罗马数字转整数 - 力扣&#xff08;LeetCode&#xff09; 罗马数字包含以下七种字符: I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L …

最长不下降子序列LIS详解

最长不下降子序列指的是在一个数字序列中&#xff0c;找到一个最长的子序列&#xff08;可以不连续&#xff09;&#xff0c;使得这个子序列是不下降&#xff08;非递减&#xff09;的。 假如&#xff0c;现有序列A[1&#xff0c;2&#xff0c;3&#xff0c;-1&#xff0c;-2&…

16.大模型分布式训练框架 Microsoft DeepSpeed

微调、预训练显存对比占用 预训练LLaMA2-7B模型需要多少显存&#xff1f; 假设以bf16混合精度预训练 LLaMA2-7B模型&#xff0c;需要近120GB显存。即使A100/H100&#xff08;80GB&#xff09;单卡也无法支持。 为何比 QLoRA多了100GB&#xff1f;不妨展开计算下显存占用&…

誉天教育近期开班计划(6月15日更新)

云计算HCIP 周末班 2024/6/15 田老师 售前IP-L3 周末班 2024/6/15 陈老师 RHCA442 晚班 2024/6/17邹老师 数通HCIE 晚班 2024/6/24阮老师 云计算HCIE直通车晚班 2024/6/25 曾老师 售前IT-L3 周末班 2024/6/29 伍老师 数通HCIP 晚班 2024/7/1杨老师 存储直通车 晚班 2024/7/1 高…