方法
方法的意义
-
每种编程语言中都有方法的概念,也称为:函数、过程
-
作用:用于封装一段特定的业务逻辑功能
System.out.println("Hello"); // 输出一个Hello
int a = scan.nextInt(); // 扫描一个整数
double b = scan.nextDouble(); // 扫描一个浮点数
double c = Math.random(); // 生成一个随机数
System.arraycopy(a, 1, b, 0, 4); // 按规则从一个数组Copy到另一个数组
int [] b = Arrays.copyOf(a, 6); // 按规则从一个数组Copy到另一个数组
Arrays.sort(arr); // 对一个数组进行排序
-
建议:方法应该尽可能独立,一个方法只做一件事
-
方法可以被反复多次调用,感受一下刚才的代码中的每一个方法是否是这样的
System.out.println("Hello"); // 输出一个Hello
int a = scan.nextInt(); // 扫描一个整数
double b = scan.nextDouble(); // 扫描一个浮点数
double c = Math.random(); // 生成一个随机数
System.arraycopy(a, 1, b, 0, 4); // 按规则从一个数组Copy到另一个数组
int [] b = Arrays.copyOf(a, 6); // 按规则从一个数组Copy到另一个数组
Arrays.sort(arr); // 对一个数组进行排序
-
优点:可以减少代码重复,有利于代码的维护
-
什么时候用:只要是一个独立的业务功能,就封装到一个方法中
int [] arr = new int [10];
for (int i = 0; i < arr; i ++) {
arr[i] = (int)(Math.random() * 100);
System.out.println(arr[i]);
}
// 这段代码我们在day05的包内ArrayDemo、MaxOfArray、ArrayDemo中都用到了
// 是否可以把以上代码作为一个方法
// 可供我们随时使用
// 这样就减少了代码的重复
// 如果我们要修改代码
// 也不需要将每一个类中修改了
// 只需要修改方法
方法的定义
定义方法
-
定义方法的五要素:修饰词、返回值类型、方法名、参数列表、方法体
-
修饰词:统一先使用
public static
-
返回值类型:方法可以有返回值,也可以无返回值
-
无返回值:返回值类型统一写成void,一般地应用于:
-
打印输出(如上面的例子)。
-
改变对象的状态(修改对象属性等)。
-
执行某个动作(比如显示一个对话框)。
-
-
有返回值:返回值类型写成特定的数据类型即可,一般地应用于:
-
计算数值(例如加法、乘法等)。
-
判断条件(返回布尔值
true
或false
)。 -
获取信息(例如获取字符串长度)。
-
-
// 我们注意到这几个方法的使用过程没有出现“=”,我们称为无返回值 System.out.println("Hello"); // public static void System.arraycopy(a, 1, b, 0, 4); // public static void Arrays.sort(arr); // public static void // 我们注意到这几个方法的使用过程都出现了“=”,我们称为有返回值 int a = scan.nextInt(); // public static int double b = scan.nextDouble(); // public static double double c = Math.random(); // public static double int [] d = Arrays.copyOf(a, 6); // public static int
-
何时有返回值?何时无返回值?上面可能有些难以理解,我们看下面的解释:
-
方法执行完之后:
-
若还需要用到方法中的数据:有返回值
-
若不需要用到方法中的数据:无返回值
-
-
通俗地讲:
-
**无返回值方法:**就像你去跑步,目的是为了锻炼身体,跑完之后就结束了,并不需要拿什么东西回来。
-
**有返回值方法:**就像是你去商店买面包,你去了商店(调用了方法),买到了面包(得到了返回值),然后把面包带回家(返回给调用者)。
-
-
// 我们注意到这几个方法的使用过程没有出现“=”,我们称为无返回值 System.out.println("Hello"); // 输出完成就结束了,不需要再次使用,无返回值 System.arraycopy(a, 1, b, 0, 4); // 复制之后不需要再次使用,无返回值 Arrays.sort(arr); // 排序后无需再次使用,无返回值 // 我们注意到这几个方法的使用过程都出现了“=”,我们称为有返回值 int a = scan.nextInt(); // 给a赋值,还需要用到a,有返回值 double b = scan.nextDouble(); // 给b赋值,还需要用到b,有返回值 double c = Math.random(); // 给c随机,还需要用到c,有返回值 int [] d = Arrays.copyOf(a, 6); // 复制给d,还需要用到d,有返回值
-
方法名:见名知意
-
参数列表:括号里有东西就是有参数
-
方法可以有参数,也可以无参数
-
有参可以使方法更为灵活
-
// 我们注意到这几个方法的使用过程没有出现“=”,我们称为无返回值 System.out.println("Hello"); // 有参数 System.arraycopy(a, 1, b, 0, 4); // 有参数 Arrays.sort(arr); // 有参数 // 我们注意到这几个方法的使用过程都出现了“=”,我们称为有返回值 int a = scan.nextInt(); // 无参数 double b = scan.nextDouble(); // 无参数 double c = Math.random(); // 无参数
// 有参会令方法更为灵活 double c = Math.random(); // 只能生成0.0到0.999999...之间的随机数 double c = Math.random(1, 1000); // 生成1到1000之间的随机数 // 是否感受到有参数使方法变得更灵活了?
- 方法体:具体业务的逻辑实现
// 方法1: public static void say() { // 业务逻辑实现... } // 方法2: public static int sum(int num1, int num2) { // 业务逻辑实现... }
- 示例代码:
package day06; public class MethodDemo { public static void main(String[] args) { /* public static:修饰词 void:返回值 —— 无返回值 main:方法名 String[] args:参数列表 {内部}:方法体 */ } // 无参无返回值方法 // 计算机执行时只执行main方法,我们需要在main方法中调用该方法 public static void say() { System.out.println("大家好,我是Zhang,今年21岁了!"); } }
-
方法的调用
- 无参数无返回值的方法调用:
方法名();
package day06;
public class MethodDemo {
public static void main(String[] args) {
/*
public static:修饰词
void:返回值 —— 无返回值
main:方法名
String[] args:参数列表
{内部}:方法体
*/
// 调用say()方法:
say();
say(); // 我们不止可以调用1次,还可以多次调用
System.out.println("-OVER-");
}
// 无参无返回值方法
// 计算机执行时只执行main方法,我们需要在main方法中调用该方法
public static void say() {
System.out.println("大家好,我是Zhang,今年21岁了!");
}
}
- 有参数无返回值的方法调用:
方法名(参数1,参数2, ...);
package day06;
public class MethodDemo {
public static void main(String[] args) {
/*
public static:修饰词
void:返回值 —— 无返回值
main:方法名
String[] args:参数列表
{内部}:方法体
*/
// 调用say(无参)方法:
say();
say();
System.out.println("——————————————————————————");
// 调用sayHi(有参)方法:
sayHi("Zhang", 21);
sayHi("Jiang", 21);
System.out.println("——————————————————————————");
System.out.println("-OVER-");
}
// 无参无返回值方法
// 计算机执行时只执行main方法,我们需要在main方法中调用该方法
public static void say() {
System.out.println("大家好,我是Zhang,今年21岁了!");
}
// 上面的方法明显把名字年龄都写死了,如果想把方法写活,可以通过加参的方式
// 有参无返回值方法
public static void sayHi(String name, int age) {
System.out.println("大家好,我是" + name + ",今年" + age + "岁了!");
}
}
形参:形式参数,定义方法是的参数称为形参
实参:实际参数,调用方法时的参数成为实参
return
-
return的用法:
return 值;
计算机执行时,遇到return
先结束该方法,类似break;
,之后返回该值给调用方,注意:有返回值的方法必须有return
。
public static int sum(int num1, int num2) { int num = num1 + num2; return num; // 注意:返回的不是num变量,而是num变量里面存储着的数,返回值必须与规定的数据类型匹配,否则会产生错误 // return num1 + num2; // 用这种方式也可以返回返回值 // 注意:有返回值的方法必须写return返回 }
- 有参有返回值调用方法:
数据类型 变量 = 方法名(有参传参);
int num = sum(5, 6);
package day06; public class MethodDemo { public static void main(String[] args) { // 调用sum()方法: int twoNumSum = sum(5, 6); // sum(5, 6)的值就是return后的那个数 System.out.println(twoNumSum); // 模拟对返回值的后续操作,可以用这个返回值做任何操作,此处仅作输出示例 System.out.println("-OVER-"); } // 业务:需要返回一个两数之和的值 // 有参有返回值方法 public static int sum(int num1, int num2) { int num = num1 + num2; return num; // 注意:返回的不是num变量,而是num变量里面存储着的数,返回值必须与规定的数据类型匹配,否则会产生错误 // return num1 + num2; // 用这种方式也可以返回返回值 // 注意:有返回值的方法必须写return返回 } }
- 但是一般我们面对的业务都是传变量进方法中:
package day06; public class MethodDemo { public static void main(String[] args) { // 调用sum()方法: int twoNumSum = sum(5, 6); // sum(5, 6)的值就是return后的那个数 System.out.println(twoNumSum); // 模拟对返回值的后续操作,可以用这个返回值做任何操作,此处仅作输出示例 System.out.println("——————————————————————————"); // 一般情况下我们一般都是传变量 int m = 5, n = 6; int b = sum(m, n); // 将两个变量传入两数之和方法中进行计算 System.out.println(b); // 得出结果 System.out.println("-OVER-"); } // 业务:需要返回一个两数之和的值 // 有参有返回值方法 public static int sum(int num1, int num2) { int num = num1 + num2; return num; // 注意:返回的不是num变量,而是num变量里面存储着的数,返回值必须与规定的数据类型匹配,否则会产生错误 // return num1 + num2; // 用这种方式也可以返回返回值 // 注意:有返回值的方法必须写return返回 } }
-
return的特殊方法:
如果遇到无返回值的方法,我们也可以在其中加入
return;
返回,格式固定为:return;
package day06; public class MethodDemo { public static void main(String[] args) { // 调用sayHello()方法 String myName = "Zhang"; int myAge = 21; sayHello(myName, myAge); myName = "Liu"; myAge = 99; // 不输出,符合条件return掉 System.out.println("-OVER-"); } // 没有返回值的方法中添加返回值,可以在某种特定的条件下结束方法 public static void sayHello(String name, int age) { if (age < 18 || age > 80) { // 特殊条件规定 return; // 结束方法 } System.out.println("你好,我叫" + name + ",我今年" + age + "岁!"); } }
方法的签名
- 方法的签名:方法名+参数列表
public static void say() {}
- Java规定:在同一类中,不允许出现签名完全相同的方法
public class Test{
public static void say() {...}
public static void say() {...} // 不允许
public static int say() {return 1;} // 不允许
}
方法的重载(overloading)
-
定义:发生在同一类中,方法名相同,参数列表不同
-
绑定:编译器在编译时会根据方法签名自动绑定方法
public class Test{
public static void say() {...}
public static void say(String name) {...} // 允许
}
-
当我们使用
say();
时,Java自动调用无参的say方法 -
当我们使用
say("zhangsan");
时,Java自动调用有参方法 -
举一个实际的重载的例子:
System.out.println();
System.out.println(25);
System.out.println(3.14);
System.out.println(true);
System.out.println('a');
System.out.println("hello");
(我们知道.println
是一种方法,那如果我们写一段这样的代码为什么不报错)
public static int println() {
}
(那如果我想要输出的时String
类型的数据,为什么不报错)
是因为:
public static int println() {
}
public static int println(boolean x) {
}
public static int println(char x) {
}
public static int println(int x) {
}
public static int println(float x) {
}
public static int println(String x) {
}
(当我们调用.println
方法时,Java自动选择重载的那部分方法,执行选择的方法内部的代码)
- 实际应用中,重载的作用:
package day06;
public class MethodDemo {
public static void main(String[] args) {
/*
public static:修饰词
void:返回值 —— 无返回值
main:方法名
String[] args:参数列表
{内部}:方法体
*/
// 调用say(无参)方法:
say();
say();
System.out.println("——————————————————————————");
// 调用say(有参)方法:
say("Zhang", 21);
say("Jiang", 21);
System.out.println("-OVER-");
}
// 无参无返回值方法
// 计算机执行时只执行main方法,我们需要在main方法中调用该方法
public static void say() {
System.out.println("大家好,我是Zhang,今年21岁了!");
}
// 上面的方法明显把名字年龄都写死了,如果想把方法写活,可以通过加参的方式
// 有参无返回值方法
public static void say(String name, int age) {
System.out.println("大家好,我是" + name + ",今年" + age + "岁了!");
}
}
(这里在调用时就可以自主选择到底要调用无参方法还是有参方法,又参方法有需要什么方法)
重载容易犯错的一些地方
-
参数列表完全相同:
方法重载要求方法具有不同的参数列表。如果两个方法除了返回类型外其他都相同,则不会被视为重载,并会导致编译错误。
// 错误示例
public class Example {
public int add(int a, int b) {
return a + b;
}
public double add(int a, int b) { // 错误:参数列表相同
return a + b;
}
}
-
只通过参数名称区分:
方法重载不能仅仅依靠参数名称的不同来区分不同的方法。
// 错误示例
public class Example {
public void display(String message) {
System.out.println(message);
}
public void display(String msg) { // 错误:参数名称不同但类型相同
System.out.println(msg);
}
}
- 类型转换导致歧义
当存在多个重载方法并且参数可以通过自动类型转换匹配多个方法时,可能会导致编译器无法确定选择哪个方法。
public class Example {
public void display(int a) {
System.out.println(a);
}
public void display(long a) { // 长整型
System.out.println(a);
}
public static void main(String[] args) {
Example e = new Example();
e.display(123L); // 错误:编译器无法确定调用哪一个
}
}
Debug调试工具:
-
错误:
-
编译错误 ——— 最简单、最好找的
-
运行时异常 ——— 会告诉具体是那句有问题
-
不报错,但最不好 ——— 找程序的运行结果与预期结果不符合
-
-
Debug 调试工具:快速找到错误位置
-
添加断点:点击想添加断点的一行的前面
-
Debug运行程序,程序会自动进入第一个断点处,暂停
-
F7:逐步调试(单步调试),会进入到方法中
-
F8:逐过程调试,不会进入到方法中
-
F9:直接跳到下一个断点处,若后方无断点,则调试结束
-
-
评委打分程序
需求:《主持人大赛》有N位评委给选手打分
选手的最终得分为:去掉最高分和最低分之后的(N-2)位评委的平均分
分
要求:使用方法实现
package day06;
import java.util.Arrays;
import java.util.Scanner;
/*
需求:《主持人大赛》又N位评委给选手打分
选手的最终得分为:去掉最高分和最低分之后的N-2位评委的平均分
要求:使用方法实现
*/
public class CalTotalAvg {
// 主方法
public static void main(String[] args) { // 撒贝宁要干的
double [] scores = inputScore(6); // 录入评委的评分
double avg = calAvg(scores); // 计算平均分
System.out.println("平均分为:" + avg);
}
// 该方法用于录入N位评委的评分
public static double[] inputScore(int n) {
double [] scores = new double[n]; // 评分数组
Scanner scanner = new Scanner(System.in);
for (int i = 0; i < scores.length; i++) {
System.out.println("请录入第" + (i + 1) + "位评委的分数");
scores[i] = scanner.nextDouble();
}
return scores;
}
// 该方法用于计算平均分
public static double calAvg(double[] scores) {
double total = 0.0; // 总分
double max = scores[0];
double min = scores[0];
for (int i = 0; i < scores.length; i++) {
total += scores[i]; // 累加所有评分
if (scores[i] > max) { // 找最高分
max = scores[i];
}
if (scores[i] > min) { // 找最低分
min = scores[i];
}
}
// 计算平均分———总分剪掉最高分和最低分后,÷(评委数-2)
double avg = (total - max - min) / (scores.length - 2);
return avg;
}
}
死循环版猜数字
package day06;
import java.util.Random;
import java.util.Scanner;
public class Guessing {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Random random = new Random();
int num = random.nextInt(1000) + 1; // 1到1000
System.out.println(num); // 作弊
while (true) {
System.out.println("猜吧!");
int guess = scanner.nextInt();
if (guess > num) {
System.out.println("猜大了!");
} else if (guess > num) {
System.out.println("猜小了!");
} else {
System.out.println("猜对了!");
break;
}
}
}
}