Skip to content

Latest commit

 

History

History
220 lines (137 loc) · 9.11 KB

Lesson09.md

File metadata and controls

220 lines (137 loc) · 9.11 KB

Lesson 09 - 静态方法

假设我们要判断一个数是否是一个质数,你会直接将代码写出来,可能需要花上将近十行代码。但是假设你在做一个大型的project,在这个project中你要不停地判断新接收到的数是否是质数,要判断几十多次,这个时候,你如果直接将判断写在程序里,那就是得几百多行。是否有一种方法,可以将一部分操作相同的代码组合到一起呢?这就要讲到我们这节课的内容——方法。

1 定义

**方法(Method)**是为完成一个操作而组合在一起的语句组。

方法就像一个流水线,为了设计一个流水线,需要明确以下几个内容:

  1. 流水线需要什么零件
  2. 这些零件应该如何组装到一起
  3. 最后的产品是什么

依此类推,设计一个方法所需要的内容则为:

  1. 方法接收什么输入
  2. 对这些输入应该如何处理
  3. 最后输出的结果是什么

在你有了这些“流水线”后,每次你想要某个操作的结果,只需要去定义一个相应的“流水线”,再每次直接使用这个”流水线“就可以了。

2 方法的声明

那么就让我们来看看怎么声明一个方法:

public static int max(int num1, int num2) {
    if(num1 > num2)	return num1;
    else			return num2;
}

上面的代码声明了一个名叫max的方法,这个方法可以求出两个数中最大值并作为返回值返回出来。这样我们每次需要取两个整数的最大值时,都可以使用这个方法。

让我们一起从上往下深入地剖析一下这个方法的每一个部分:

  • public:这个是可见性修饰符(Access Modifiers),等到以后学到了其他的可见性修饰符再细说吧
  • static静态修饰符,表示这个方法是一个静态方法,等我们以后学到了实例方法再做分析吧
  • int:写在方法名前面的类型表示这个方法的返回值类型(return type),这里表示这个方法返回一个int类型的变量。什么是返回值呢?其实就是一个方法的运行结果,就像1+1运行结果是2一样
  • max方法的名字,我们需要用这个名字去区分要调用的方法
  • (int num1, int num2)参数列表,这里表示我们要接受两个int类型的参数,接收到的数据被复制后将存放在num1num2这两个变量中,之后方法体内的语句想要使用输入的参数就直接使用这两个变量即可
  • line 2、3方法体(method body),定义了这个方法内具体要进行的逻辑操作;我们这里是判断num1num2的大小,最后返回大的那一个
  • return xxx:通过return关键词指明要返回的值,当方法执行到return后会立刻结束,带着返回值回到调用这个方法的地方继续往后执行

void

方法其实不一定非要有一个返回值,比如一个只是可以将一些数据漂漂亮亮地输出出来的方法:

public static ? printGrade(String name, String studentID, double grade) {
    System.out.printf("     Name: %8s\n", name);
    System.out.printf("StudentID: %8s\n", studentID);
    System.out.printf("    Grade: %8.1f\n", grade);
}

这个时候你应该将这个方法的返回值类型声明为voidvoid英文本义为虚空的,在这里表示一个方法什么也不返回。如果你想要提前结束一个返回值为void的方法,可以直接使用return;

3 方法的调用

我们刚刚声明了一个叫max的方法,但是我们该怎么去调用invoke,计算机术语,使用的意思)这个方法呢?调用之后又进行了怎么样的过程呢?

int i = 28, j = 23;
int k = max(i, j);

上面代码块的第二行就调用了max方法,我们使用方法名加上一个小括号,括号内是要传递给方法内部的一些参数。

当程序运行到第二行时,程序发现此处等号右边在调用max方法,就会继续去执行这个方法里的语句。同时,入参的ij的数据值会被复制给方法内的num1num2两个变量。最终,经过max方法的一番操作,较大的值被返回出来,作为max(i, j)的结果赋值给了k

注意:这里的传参过程进行的是数据值的复制,所以无论我们怎么改变方法内的num1num2,方法外的变量ij不会有任何改变。

4 main方法

终于学到了这一节,让我们来重新认识一下我们的老朋友:main方法

public static void main(String[] args) {
    ...
}

深入剖析,我们发现main方法……

  1. 全世界可见(public)
  2. 静态方法(static)
  3. 不返回值(void)
  4. 方法名为main(不是废话么:sweat_smile:)
  5. 接收的参数为String类型的名为args一维数组:这个就是之前学到的使用Arguments入参作为输入的承载体喔~

5 为什么我们要使用方法

  1. 增加代码的复用性:类似这篇课件开头的例子,当我们将判断质数的代码放在一个入参为待测数,返回值为是否是质数的方法中。每次我们直接调用这个方法而不是再写一遍判断质数的代码,这大大减少了代码的长度。
  2. 易于debug:由于每次调用方法,我们都使用的是同一块代码。这块代码如果出现了逻辑错误,我们可以一次性地、通过修改这块代码的内容来解决问题。但若我们将其分开,每次都再写一遍判断质数的代码,假设后来你发现你的代码有问题,比如大于符号和小于符号写反了,你就需要在你长长的代码中找到你在哪些地方写了这个判断,你要保证每一个你都有改正,可一不小心你就会改漏。
  3. 模块化代码:其实很多时候我们并不一定是为了减少重复的代码,我们也可能只是将步骤繁复的代码分成多步,分到好几个方法内。比如想象makeMove方法是你需要写的一个黑白棋(今年JavaA的project)人机代码:
public static void makeMove(){
    searchValidPlaces();
    comparePlaces();
    makeBestMove();
    updateChessBoard();
}

​ 我们将逻辑分布在四个方法里面,每个方法做相应的操作:开始我们先选哪里可以下,再比较可以下的地方下哪里最好,之后我们下最好的那一步,最后更新棋盘。这些的具体逻辑我们放在这些新的四个方法里面一一实现,这使得将一个复杂的逻辑分布,划开界限:一方面非常容易debug,你可以立刻找到哪里是你写的什么代码;另一方面你可以专注于一个小方法的实现,即一部分子逻辑的实现中。

6 方法重载(Method Overloading)

方法重载是指两个方法可以使用相同的名字,不同的参数列表。

参数列表不同涉及到两点:

  • 参数个数不同
  • 参数的类型不同

方法重载主要用于命名一系列功能相似的方法。

比如以下的两个方法,都是求最大值,一个是求两个数的最大值,一个是求三个数的最大值:

public static int max(int x, int y) {
    System.out.println("Method 1 invoked");
    if(x > y)	return x;
    else		return y;
}

public static int max(int x, int y, int z) {
    System.out.println("Method 2 invoked");
    int max = x;
    if(y > max)	max = y;
    if(z > max)	max = z;
    return max;
}

在我们调用它们时:

int i = 5, j = 2;
int k = max(i,j);
System.out.println(k);
System.out.println(max(7888, 900, 232));

输出为:

Method 1 invoked
5
Method 2 invoked
7888

由此可见,调用哪个方法取决于方法名以及方法的参数列表

注意:

  1. 两个方法的返回值不同,其他相同,并不能构成方法重载
  2. 两个方法的参数变量名不同,其他相同,并不能构成方法重载

7 可变长参数列表

可以将具有同样类型的可变长度的参数传递给方法。参数声明为typename... parameterName。在方法中,可变长的参数将会被当成数组对待。

比如下面的代码,就是取可变长参数中的最大值:

public static double max(double... nums) {
    System.out.println("Method 3 invoked");
    double maxValue = Double.MIN_VALUE;
    for(int i = 0; i < nums.length; i++)
        if(maxValue < nums[i])
            maxValue = nums[i];
    return maxValue;
}

注意事项

  1. 方法中只能指定一个可变长参数
  2. 可变长参数必须是参数列表中的最后一个参数

更典型的例子

System.out.printf方法!

8 方法调用栈*

因为涉及到课外(计算机组成原理以及数据结构)的知识,在这里我们就不细讲啦,所以大家有兴趣可以自己了解一下哈。

写在后面的话

恭喜各位!学到这里,你们的编程就入门啦!你们到目前为止学习的(变量、判断、循环、数组、方法)是学习每门编程语言都会学到的内容。

接下来,就让我们走上Java所特有的面向对象编程思想的困难旅程吧!向着星尘与深渊!