课时28:数组与方法

简介: 本次分享的主题是数组与方法。主要分为四个部分:1.数组与方法之间的交互2.定义返回数组的方法3.内存关系的分析4.数组与方法的关系

课时28:数组与方法

摘要:本次分享的主题是数组与方法。主要分为四个部分:

1.数组与方法之间的交互

2.定义返回数组的方法

3.内存关系的分析

4.数组与方法的关系

 

 

01.数组与方法之间的交互

 

接下来看一下数组与方法之间的交互。引用数据类型的主要特点是它可以与方法进行引用传递,而数组本身也属于引用类型。因此它自然也可以通过方法实现引用传递的操作。那么该怎么做?比如来看一下下面的例子,来实现一个数组的引用传递。比如现在编写一个简单的程序。


代码可以这样写:首先声明一个名为 Int Date 的变量,并给它赋一个值称之为 New Int ,并随意给它赋一个值,比如 12345 。随后编写一个方法命名为 Public 。很明显这个 Public 方法需要接收一个 Int 类型的数组作为参数,那么代码中是否可以直接将 Date 变量作为单个元素传递到这个数组中?这个数组在这个过程中的作用很简单,它只是想要进行打印操作。


具体来说就是遍历数组,对于每个元素 X ,如果 X 小于 Temp的某个特定值,则X++

完成遍历后使用 System.out.print 方法打印数组 Temp 

image.png

public classArrayDemo{
public static voidmain(String args[]) {
int.data [] = new int[] {1,2,3,4,5};
}
public static void printArray(int temp[]) {}
}

现在来观察程序代码。在 Java 中创建一个名为 ArrayDemo  Java 文件,并执行 ArrayDemo 程序。可以看到程序正常完成了执行,并输出了 12345 。因此已经实现了一个最为简单的引用传递示例。那么具体的内存关系还是需要绘制一下,下面就来绘制它,因为这个例子比较简单,那么就以这个程序为例,即刚才提到的 NewInt = 12345 


按照之前的绘制方法应该准备一个数据区域。这个数据区域在编写时很明显,为了示例定义了五个位置。那么这里面是不是还需要记录一些其他信息?比如数值 12345 。而具体内容是怎样的?1 跟上, 2 再跟上, 3 再跟上4 再跟上,最后是 5 ,这样就实现了速度定义。

image.png

Int data[]=new int[]{1,2,3,4,4};

当执行一个名为 Print 的函数,并传入一个名为 Date 的参数进行处理时,实际上在代码层面程序中会有一个变量 Temper 。这个Tmper 变量将会指向与 Date 相同的内存空间引用。因此最终的结果是不是相当于 Temper 也会输出这块内存中的数据?这是一个最为简单,也是最为标准的引用传递的操作示例。

image.png

现在按照这个过程继续分析,现在已经实现了方法参数接收一个数组的功能那么反过来思考既然方法可以接收一个数组作为参数,那么同样地方法也可以通过返回值返回一个数组对象。此时只需要在方法的返回值类型上进行相应的设置即可。

 

02.定义返回数组的方法

 

在这个程序中代码可以这样写。为了简洁明了直接定义一个 Public Static 方法,返回类型为 Int[] 给这个方法命名为 InitArray 。这里的 Int[] 表示该方法将返回一个整型数组。比如创建一个名为 Int Arr 的数组,这个数组是通过一个方法返回的。但是在声明数组时这里必须加上什么?即用大括号表示的是数组的定义。


那么在程序中代码可以这样写: Int[] Arr = New int[]{1, 2, 3, 4, 5} ;,而后 Return Arr ;。很明显这个地方返回的是一个数组,那么能够接收它的也必然是一个数组。


所以初始化数组是可以的。那么就意味着通过我们的方法可以获取数组的内容。现在来查看一下这个结果,它应该与之前的结果没有差别。如果现在的代码是这样写的,那么这种效果是否被称为匿名数组?但是在提到匿名数组时,首先编译并执行一下代码,看看是否正常工作。


然而如果你尝试使用简化的写法,那是不对的,这是不正确的简化方式当这样执行时它是不是会报错?因此之所以建议大家不要去依赖简化写法,是因为在编写代码时如果使用匿名数组必须提供完整的类型信息


image.png

public class ArrayDemo{
public static void main(String args[]){
int data []=initArray();//通过方法可以获得数组内容 printArray(data); //传递数组
  }
public static int [] initArray(){
int arr [] = new int[]{1,2,3,4,5);
return arr ; // 返回一个数组
  } 
// 要求接收一个int型的数组
public static void printArray(int temp []){
for (intx=0;x< temp.length ;x++){
System.out.println(temp[x]);
}
  }
}

 

03.内存关系的分析

 

接下来将针对这个程序进行内存关系的分析。首先把程序直接展示出来。按照之前的程序做法将在这里进行数组与方法的分析。这是第一步。在第一步中应该关注的是哪个方法进行了初始化。以及在初始化这个方法里它执行了什么操作?有一个变量 Arr ,所以在这段代码中实际上这个方法在这里实现的操作就相当于我们定义了一个名为 Arr 的数组


接下来进行第二步,返回之后,当执行这句话时其本质就相当于什么?即 Da ,这个 Da 将指向与 Arr 相同的操作空间,然后第三步当执行 PrintArray 之后,或者当直接调用 PrintArray 之后,这个地方描述的是什么概念?实际上与刚才相比,这里又多了一个名为 Temp 的指向。这并不复杂。只不过与之前的代码相比现在最大的特征在于是通过一个方法来获得了所需的实例化对象再往下看除了能够通过方法获得对象之外,还可以做一件什么事情?接下来看一下程序。比如可以通过方法来修改数组的内容。


现在有这样一段程序代码,为了简单起见暂时不考虑返回操作。在这里希望定义一个方法称之为 Y 。这个方法会接收一个名为 Arr 的整数数组作为参数。在方法的代码中使用一个 For 循环,定义一个整数变量 X ,从 0 开始,直到 X 小于 Arr 的长度,每次循环 X 自增1 。在循环体内将 Arr 数组中索引为 X 的元素乘以 2 ,即 Arr[x] * = 2 。这句话的含义是将数组中的每个元素的内容乘以 2 并保存。现在完成了一个操作即将数组中的每个元素都乘以 2 并保存。


那么现在在这里调用这个方法,称之为 ChangeArray ,并传入一个数组作为参数,目的是修改这个数组的内容。现在来看一下最终的结果编译并再次执行程序后,大家可以看到输出结果为 2  4  6 、8  10 ,这是因为原来的数组 1  2  3  4  5 中的每个元素都被乘以了 2接下来分析一下这道程序的内存关系。这是本程序的内存关系继续来观察这道程序的内存关系图。


image.png

public class ArrayDemo{
public static voidmain(String args[1){
int data [] = new int[] {1,2,3,4,5}; 
changeArray (data); // 修改数组内容 
printArray (data); //传递数组
  }
public static voidchangeArray (intarr[]){
for (intx=0;x<arr.length;x++){
arr[x] *=2 ; // 每个元素的内容乘2保存
}
 }
// 要求接收一个int型的数组
public static void printArray(int temp []) {
for (intx=0;x<temp.length;x++) {
System.out.println(temp[x]) ;
}
  }
}


04.数组与方法的关系

 

首先这个程序的第一步操作与之前类似,相当于现在在这个地方准备了一个数组。而后数组命名为 Data 并且 Data 这个地方是进行第一步先期保存的位置。紧接着要执行的是第二步,即调用ChangeArray 方法。一旦执行到这一步整个过程中就涉及到了引用传递。


如果要明确体现引用传递的代码形式应该在这里有一个 Arr ,它指向一个内存空间,这个内存空间存储了我们的数组数据。然后调用 ChangeArray 方法,并传入 Arr 作为参数,以修改 Arr 所指向的内容。在修改 Arr 内容的过程中,无论是否采用循环,有一点是确定的:数组中的所有元素都会被乘以 2 ,从而变成 2  4 、6  8  10


完成方法之后是否还需要 Arr 继续占用那块内存引用?既然这个方法已经结束,它也就完成了使命。那么 Arr 结束之后会怎样?它会消失。当 Arr 消失后,如果代码中紧接着又出现了一个名为 PrintArray 的函数,并执行 PrintArray 的操作,对于整个程序而言这相当于在这里重新准备了一个东西。就像之前提到的 Temp 变量,现在 Temp 再去指向那块内存空间,并进行内容的输出。所以这就是整个程序执行流程的一个分析。

image.png

在这样一个分析过程中无论是否存在方法,引用传递的本质并没有发生改变。始终都是同一块内存地址被不同的引用所指向接下来通过一个综合案例来进一步说明。比如可以定义一个数组,要求能够计算出这个数组元素的总和。这里以一个 Int 数组为例,其实无论是哪种类型的数组,原理都是一样的。因为不仅要计算出这个数组元素的总和,还要求出它的最大值、最小值,以及平均值。

System.out.println(temp[x]);
      }
   }
}

现在定义一个数组,并将其放在代码中。为了简化说明不添加其他复杂的部分,就用这个数组来举例。请注意除了保留PrintArray 之外,其他部分都先不考虑。这个地方是关于打印速度输出的数据,之后就用这些数字来进行计算,求出总和、最大值、最小值和平均值。首先平均值、总和以及平均值相对容易求解。


关于总和的计算可以这样表示:首先定义一个变量叫 Int sum = 0 。接下来为了计算平均值可以定义一个 Double 类型的变量,不考虑精度问题,也可以先这样声明,即 Double AVG = 0.0这两个变量的初始化很简单。如果要直接进行计算通常会遍历一个数据集,比如使用循环 For (int x = 0; x < data.length; x++) ,这里的Data 是假设的数据数组。

 

  image.png

public class ArrayDemo {
public static void main(String args[]) {
int data [] = new int[]{1,2,3,4,5}; 
int sum =0;
I
  }
public static void printArray(int temp [1){
for (intx=0 ; x< temp.length ;x++) {
System.out.println(temp[x]);
   }
}
}

X++ 完后整个代码里程序中 Sum 变量会等于多少倍的 X 。随后计算 AVG ,它是 Sum 除以 Data.length 的结果。完成这些计算后,使用 System.out.print 来输出结果。在这里输出一个称为“最大值”的变量,这个叫做“总数组和”,然后再输出一个叫做“数组内容平均值”的变量。


那么这个地方缺少了一个索引,完成这一步之后再来查看一下结果。编译并执行程序到这里,而这个过程求出总和相对比较简单,但还存在问题。那么最大值和最小值是怎么求的?它们的求解方法是这样的:首先假设第一个元素是最大值,同时也是最小值。即假设第一个元素是最大值 Int Max ,并初始化一个变量 Int Min  0 ,而后进入循环。


在循环中进行比较:如果当前元素比 Max 大,则更新 Max 为该元素的值;如果当前元素比 Min 小,则更新 Min 为该元素的值。那么这个过程应该怎么写?

image.png

public class ArrayDemo {
public static void main(String args[]) {
int data [] = new int []{1,2,3,4,5}; 
int sum =0;;
double avg =0.0 ;
int max=data[0];
int min
for (int x =0 ; x< data,length ;x++){
sum += data[x];
    }
avg = sum 1/ data.length;
System.out.println("数组内容总和:"+ sum) ; System.out.println("数组内容平均值:"+ avg) ; 
  }
public static void printArray(int temp [1){
for (int x=0 ;x<temp.length ;x++) {
system.out.println(temp[x]) ;
    }

如果现在假设有一个日期值 DateX ,它大于当前的 Max ,这意味着 Max 的地位需要改变了,那应该怎么做?很简单将 Max 更新为DateX 的值。反过来如果 DateX 比之前记录的 Min 还小,那么这里应该先更新Min 的值,将其改为 DateX 


于是在这个逻辑下可以编写相应的代码。当把这段代码放到程序中,并且再添加一部分代码来分别跟踪数组中的最大值和最小值,之后在某个地方打印出Max Min 的值。当程序编译并再次执行时会发现它成功地找到了数组中的最大值和最小值。


但有个问题既然要写这个程序,肯定不能按照刚才那种直观但低效的方式去做。对于程序的最基本实现接下来会展示给大家。但为什么不能按照那种方式去做?首先要清楚第一个问题:主方法。主方法所在的那个类通常称之为主类,既然是主类肯定不希望它涉及到过于复杂的功能。


那么什么叫过于复杂的功能?来举个最简单的例子。就好比电脑开机,我们都知道怎么操作,只需按下一个按键就能启动,这个过程并没有特别复杂的功能。但是如果要按照那种复杂的代码编写方式去开机,好比你是客户端,在开机过程中需要深入到电脑的每一个细节去操作,这样显然过于复杂了。因此现在的最佳做法不是将复杂的代码逻辑直接放在主方法中,而是应该设计一个更简洁、更高效的方案来完成任务。

image.png

int sum=0;; 
double avg =0.0;
int max = data[0];1假改第一个是最大值 
int min = data[0] ; //假设第一个是最小值 
for (int x = 0 ;x< data.length;x++{
if (data[x]> max) { // max地位改变了 
max = data[x]
    }
if (data[x] < min){
min = data[x];
    }
sum += data [x];
}
avg = sum / data.length ;
System.out.println("数组内容总和:"+sum); 
System,out.println("数组内容平均值:"+avg);
System.out.println("数组内容最大值:"+max); 
System.out.printin("数组内容最小值:"+min);

那么应该怎么做?在开发过程中主方法本身就相当于一个客户端的角色。对于客户端的代码应该尽量保持其简洁性。因此最好的做法是将这一系列的计算过程交给单独的模块或程序去完成。


接下来看一下设计改善方案。虽然这个设计确实能够解决问题,但在实现过程中发现整个代码结构变得有些复杂了。现在特别希望设计一个名为 ArrayUtil 的操作工具类,它绝对不再是一个简单的 Java 类那么最终需要从这个工具类中获取几个数值?比如说现在需要的是 Int Sum 来保存总和


接下来再定义一个 Private Double Avg ,这个变量用来保存平均值。此外还需要一个 Int Max 来保存最大值,以及一个 Int Min 来保存最小值

image.png

class ArrayUtil{
}
public classArrayDemo {
public static void main(String args[1) {
int data [] = new int[] {1,2,3,4,5}; 
int sum =0;:
double avg =0.0;
Int max = data[0] ; // 假设第一个是最大值 
int min =data[0] ; // 假设第一个是最小值 
for (intx=0 ; x<data.length ;x++){
if (data[x]> max) { // max地位改变了
max = data[x] ;
}
if(data[x]< min){
min = data[x];
}
sum += data[x];
   }

关于这个过程最终得到的是一个统计结果。那么是不是得到这个统计结果就可以了?严格来说这里应该提供一个 Scatter 方法,而不是使用 setter 方法,因为这些值通常不需要手动设置这些值并不是通过外部输入计算得来的,如果它们是计算得出的,那就不需要设置它们了。比如计算出平均值后,紧接着可能会有一个方法叫做 Int Guid Max 


在这个过程中可以直接返回 This.max 。同样地可以直接在这里返回 This.mean 以及最小值可以直接返回 This.min 。这样就完成了这些方法的编写。

image.png

class ArrayUtil { //是一个操作工具的类 
private int sum ;//保存总和
private double avg ; //保存平均值 
private int max ; //保存最大值 
private int min ; //保存最小值
}
public class ArrayDemo {
public static void main(String args[]) {
int data [] = new int[] {1, 2,3,4,5}; 
int sum =0;;
double avg = 0.0;
int max = data[0] ; // 假设第一个是最大值  
int min = data[0]; // 假设第一个是最小值 
for (int x =0;x<data.length ; x ++){
if (data[x] > max) { // max地位改变了 
max = data[x] ;

写完之后来说一下数组操作的部分,它主要是为了计算而存在的那么就按照这样的思路来写。艾瑞克提醒我们要在这里传入一个参数。接下来来进行数组的计算。关于这个过程怎么写可以采用最简单的方法,直接对数组进行操作。可以把需要的数据拿过来进行计算。那么能不能把这些操作都集中到这里来做?当然可以。这样代码会更加清晰和有条理。


在这个过程中要确保每一步都跟上,不要遗漏。同时大家在写代码的时候,要注意这次也要使用 This来引用类的属性,就像之前说过的那样。当然不要忘了处理一个假设的最大值和最小值问题,这是数组操作中常见的一个需求。

image.png

class ArrayUtil { //是一个操作工具的类
private int sum ; // 保存总和
private double avg ; //保存平均值 
private int max ; // 保存最大值 
private int min ; //保存最小值
public ArrayUtil(int data[]) { // 进行数组计算
for (int x= 0 ; x<data.length ; x ++) {
if (data[x]> max) {// max地位改变了
max = data[x] ;
      }
if (data[x]< min) {
min = data[x] ;
}
sum += data[x] ;
    }
avg = sum / data.length ;
}
public int getSum(){

那么应该在这个过程中关注什么?关于 This.max 需要把这个任务交给一个团队去处理,这样处理之后外部的流程就不会再这么复杂了。在整个流程中的程序都会被替换掉。接下来说明一下 RVUT ,之前提到的 UT 将会被新的 RVUT 所替代,来传递的数据和计算过程


接着会基于 UT. 找到一个叫做 Sum 的功能点,再基于另一个UT. ,结合 AG 功能,找到一个 UT. 来实现 Get Max 的功能,以及再基于另一个 UT. 来实现 Get Mean 的功能。目前这个方法中暂时还没有用到这些,所以先暂时移除它们,以防混淆。等需要的时候再恢复过来。

image.png

}
}
public class ArrayDemo{
public static void main(String args[]) {
int data [] = new int[] {1,2,3,4,5}; 
int sum =0i;
double avg = 0.0;
int max = data[0] ; // 假设第一个是最大值 
int min = data[0] ; // 假设第一个是最小值 
 
System.out.println("数组内容总和:"+sum) ;
System.out.println("数组内容平均值:"+avg) ;
System.out.println("数组内容最大值:"+max) ;
System.out,println("数组内容最小值:"+ min) ;
  }
public static voidprintArray(int temp [1) {
for (intx=0;x<temp.length ; x++) {
System,out,println (temp[x]);

image.png

}
}
public class ArrayDemo{
public static void main(String args[]) {
int data [] = new int[] {1,2,3,4,5}; 
ArrayUtil
System.out.println("数组内容总和:"+sum) ;
System.out.println("数组内容平均值:"+avg) ;
System.out.println("数组内容最大值:"+max) ;
System.out,println("数组内容最小值:"+ min) ;
  }
public static voidprintArray(int temp [1) {
for (intx=0;x<temp.length ; x++) {
System,out,println (temp[x]);
}
  }
}

接下来编译一下代码,并再次执行。看看结果是否与预期一致。现在对于主类设计是不是就像客户端一样?那么主类的代码量是不是会得到很大程度的减少?


在这个设计下主类的作用就好比使用电脑时一样,只关心如何进行操作,而不需要深入了解具体的操作过程。这些具体的操作过程已经被封装起来了通过这样的封装可以更加专注于操作本身,而无需担心底层的实现细节。

image.png

}
}
public class ArrayDemo{
public static void main(String . args[]){
int data [] = new int [] {1,2,3,4,5};
ArrayUtil util = new ArrayUtil (data) ; //数据计算 System.out.println("数组内容总和:"+ util.getSum()) ; System.out.println("数组内容平均值:"+ util.getAvg() ) ; System.out.println("数组内容最大值:"+ util.getMax()) ; System.out.println("数组内容最小值:"+ util.getMin()) ;
}
}

也就是说现在只要知道如何将值传入,就能得到最大值和最小值。而且这个功能模块就像是一个即插即用的组件,用时直接拿来即可。但一定要记住 RVUT 已经不再是一个简单的概念了,它包含了一系列的计算过程。因此现在已经实现了数组与方法的操作,这一操作与普通方法的构造方式一模一样,只要是方法都可以接收引用类型。

public ArrayUtil(int data[]) {//进行数组计算
this.max = data[0]; //假设第一个是最大值
this.min = data[0]; //假设第一个是最小值 
for (int x = 0 ; x<data.length:x++){-
if (data[x] >max) {// max 地位改变了.
this.max = data[x]:
      }
if (data[x] <min) {
相关文章
|
安全 调度
什么是用户态和内核态?
【10月更文挑战第29天】用户态和内核态是操作系统中两个不同的运行级别和权限状态,它们相互配合,共同构成了操作系统的运行基础,为计算机系统的稳定运行和应用程序的高效执行提供了保障。
1558 31
|
8月前
|
Web App开发 搜索推荐 安全
macOS Sonoma 14.7.6 (23H626) 正式版 ISO、IPSW、PKG 下载
macOS Sonoma 14.7.6 (23H626) 正式版 ISO、IPSW、PKG 下载
741 6
macOS Sonoma 14.7.6 (23H626) 正式版 ISO、IPSW、PKG 下载
|
11月前
|
机器学习/深度学习 自然语言处理 监控
深入探索:深度学习在时间序列预测中的强大应用与实现
时间序列分析是数据科学和机器学习中一个重要的研究领域,广泛应用于金融市场、天气预报、能源管理、交通预测、健康监控等多个领域。时间序列数据具有顺序相关性,通常展示出时间上较强的依赖性,因此简单的传统回归模型往往不能捕捉其中复杂的动态特征。深度学习通过其非线性建模能力和层次结构的特征提取能力,能够有效地捕捉复杂的时间相关性和非线性动态变化模式,从而在时间序列分析中展现出极大的潜力。
|
SQL 数据采集 分布式计算
【赵渝强老师】基于大数据组件的平台架构
本文介绍了大数据平台的总体架构及各层的功能。大数据平台架构分为五层:数据源层、数据采集层、大数据平台层、数据仓库层和应用层。其中,大数据平台层为核心,负责数据的存储和计算,支持离线和实时数据处理。数据仓库层则基于大数据平台构建数据模型,应用层则利用这些模型实现具体的应用场景。文中还提供了Lambda和Kappa架构的视频讲解。
1161 3
【赵渝强老师】基于大数据组件的平台架构
|
机器学习/深度学习 存储 人工智能
EfficientTAM:Meta AI推出的视频对象分割和跟踪模型
EfficientTAM是Meta AI推出的轻量级视频对象分割和跟踪模型,旨在解决SAM 2模型在移动设备上部署时的高计算复杂度问题。该模型采用非层次化Vision Transformer(ViT)作为图像编码器,并引入高效记忆模块,以降低计算复杂度,同时保持高质量的分割结果。EfficientTAM在多个视频分割基准测试中表现出与SAM 2相当的性能,具有更快的处理速度和更少的参数,特别适用于移动设备上的视频对象分割应用。
412 9
EfficientTAM:Meta AI推出的视频对象分割和跟踪模型
|
前端开发 JavaScript 测试技术
前端自动化测试
前端自动化测试是通过使用工具和脚本自动执行测试用例的过程,旨在提高测试效率、减少人为错误,并确保Web应用的功能在不同环境和设备上的一致性与稳定性。
|
消息中间件 存储 安全
【深入浅出RocketMQ原理及实战】「底层原理挖掘系列」透彻剖析贯穿RocketMQ的消息顺序消费和并发消费机制体系的原理分析
【深入浅出RocketMQ原理及实战】「底层原理挖掘系列」透彻剖析贯穿RocketMQ的消息顺序消费和并发消费机制体系的原理分析
563 0
|
SQL 分布式计算 大数据
MaxCompute产品使用合集之如何提升sql任务并行度
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
282 1
|
云安全 运维 架构师
阿里云ACE认证含金量高不高?考试内容难不难?
IT行业可以说是现在最热门的行业之一,很多人都想在这一行有所建树,于是他们就会选择考取阿里云人才认证来帮助自己提升技能、升职加薪。
1652 1
阿里云ACE认证含金量高不高?考试内容难不难?

热门文章

最新文章