第 05 课:方法、参数、返回值、重载与作用域
本课目标
学完后,你应该能够:
- 看懂并写出一个 Java 方法。
- 区分参数、实参、返回值和
void。 - 使用
return返回结果或提前结束方法。 - 理解局部变量的作用域。
- 理解方法重载的判断规则。
- 用方法拆分程序,避免所有逻辑都塞进
main。
1. main 本身就是方法
public static void main(String[] args) {
System.out.println("程序从这里开始");
}
目前先这样理解各部分:
| 语法 | 当前含义 |
|---|---|
public | 访问修饰符,表示其他类也能访问;面向对象阶段详解 |
static | 方法属于类,可以直接通过类调用;面向对象阶段详解 |
void | 方法执行后不返回结果 |
main | 方法名 |
String[] args | 参数列表;这里接收命令行参数 |
{ ... } | 方法体,保存具体执行逻辑 |
普通方法结构:
访问修饰符 static 返回值类型 方法名(参数列表) {
方法体
return 返回值;
}
2. 无参数、无返回值的方法
public static void printWelcome() {
System.out.println("欢迎学习 Java");
}
调用:
printWelcome();
方法只定义不会自动执行,必须在 main 或其他方法中调用。
void 表示不返回计算结果,但方法仍然可以打印内容、修改对象或完成其他操作。
3. 参数与实参
public static void greet(String name) {
System.out.println("你好," + name);
}
调用:
greet("小明");
- 定义中的
String name称为形式参数(形参) 。 - 调用时传入的
"小明"称为实际参数(实参) 。 - 参数必须声明类型;多个参数使用逗号分隔。
public static void printUser(String name, int age) {
System.out.println(name + "," + age + "岁");
}
printUser("小明", 20);
调用时,参数数量、顺序和兼容类型必须匹配。
4. 返回值
public static int add(int a, int b) {
int result = a + b;
return result;
}
调用并接收结果:
int total = add(10, 20);
System.out.println(total);
- 方法声明中的
int表示该方法必须返回一个整数。 return result;把结果交给调用位置,同时立即结束方法。- 返回值类型必须与声明类型兼容。
也可以直接返回表达式:
public static int add(int a, int b) {
return a + b;
}
5. return 提前结束
public static void printScore(int score) {
if (score < 0 || score > 100) {
System.out.println("分数无效");
return; // void 方法可以单独使用 return 提前结束
}
System.out.println("分数:" + score);
}
输入无效时执行 return,后面的正常输出不会继续执行。这种写法可以减少多层嵌套。
6. 布尔返回值与短路校验
方法可以返回 boolean:
public static boolean isValidPlan(int days, double hoursPerDay) {
return days >= 1
&& days <= 7
&& hoursPerDay > 0
&& hoursPerDay <= 24;
}
这里的 && 仍然是短路逻辑运算符,从左向右判断。一旦某个条件为 false,后面的条件不再计算。
短路还可以保护方法调用:
public static boolean isUsableName(String name) {
return name != null && !name.isBlank();
}
如果 name == null,左侧为 false,右侧 name.isBlank() 被跳过,从而避免 NullPointerException。
7. 变量作用域
变量只能在声明它的 {} 范围内使用:
public static void demo() {
int outer = 10;
if (outer > 0) {
int inner = 20;
System.out.println(outer); // 可以
System.out.println(inner); // 可以
}
System.out.println(outer); // 可以
// System.out.println(inner); // 错误:inner 已离开作用域
}
方法的参数也是局部变量,只能在该方法内部使用。不同方法中的同名局部变量彼此独立。
8. 方法重载
同一个类中,方法名相同但参数列表不同,称为方法重载:
public static int add(int a, int b) {
return a + b;
}
public static double add(double a, double b) {
return a + b;
}
public static int add(int a, int b, int c) {
return a + b + c;
}
Java 根据实参的数量、类型和顺序选择方法。
只有返回值不同不构成重载,下面不能同时存在:
public static int getValue() { return 1; }
public static double getValue() { return 1.0; } // 编译错误
调用方法时不能只靠期待的返回类型判断选哪个方法。
9. 完整示例
打开 MethodBasics.java,其中包含:
void方法;- 带参数的方法;
- 返回
int、double、boolean的方法; - 使用
return提前结束; - 使用短路避免空指针。
打开 MethodOverloadDemo.java,观察 Java 如何根据参数列表选择重载版本。
10. 独立练习:学习计划方法化(完整答案)
完整答案位于 StudyPlanMethods.java。程序把职责拆成四个方法:
isValidPlan(...) // 校验输入
calculateWeeklyHours(...) // 计算时间
getStudyLevel(...) // 判断学习强度
printStudyPlan(...) // 输出报告
这种拆法比把所有代码塞进 main 更容易阅读、修改和测试。main 只负责组织调用流程。
核心调用:
if (!isValidPlan(daysPerWeek, hoursPerDay)) {
System.out.println("学习计划输入无效。");
return;
}
double weeklyHours = calculateWeeklyHours(daysPerWeek, hoursPerDay);
String level = getStudyLevel(weeklyHours);
printStudyPlan(name, weeklyHours, level);
11. 检查题与答案
问题
void表示什么?- 形参和实参有什么区别?
- 返回类型为
int的方法能否不写return? return执行后,方法后面的语句还会执行吗?add(int, int)和add(double, double)是否构成重载?- 只改变返回值类型能否构成方法重载?
- 为什么
name != null && !name.isBlank()不会在name为null时产生空指针? - 在
if代码块内部声明的变量,离开代码块后还能使用吗?
答案
- 方法不向调用者返回结果。
- 形参写在方法定义中,是接收数据的变量;实参写在调用处,是实际传入的值。
- 正常情况下不能。所有可能正常结束的路径都必须返回兼容的
int值;否则编译失败。 - 不会。
return会立即结束当前方法。 - 构成重载,因为参数类型不同。
- 不能。重载依据方法名和参数列表,不依据返回值。
&&左侧为false后发生短路,右侧方法调用不会执行。- 不能,因为变量已经离开其作用域。
12. 本课完成标准
- 能写出至少一个带参数和返回值的方法。
- 能解释
void、形参、实参和return。 - 能用多个小方法拆分
main中的逻辑。 - 能识别合法与非法的方法重载。
- 能用短路逻辑保护可能为
null的对象。
下一课学习数组:创建数组、索引、遍历、查找、最大值与数组常见越界错误。
13. 本课完整源码汇总
以后每课都把 .java 全文放进 Markdown。第 5 课的三个原始源码如下,内容与源码文件一致。
13.1 MethodBasics.java 完整源码
public class MethodBasics {
public static void main(String[] args) {
// 调用无参数、无返回值的方法。
printWelcome();
// "小明" 是传给 name 参数的实际参数(实参)。
greet("小明");
// add 方法返回 int;使用变量接住返回结果。
int total = add(10, 20);
System.out.println("10 + 20 = " + total);
// calculateAverage 返回 double,可以保存小数。
double average = calculateAverage(80, 90, 100);
System.out.println("平均分:" + average);
// isAdult 返回 boolean,可以直接放入 if 条件。
if (isAdult(20)) {
System.out.println("已经成年");
}
// 传入 null,短路运算会阻止 name.isBlank() 执行。
System.out.println("null 名称是否可用:" + isUsableName(null));
// 无效分数会让方法通过 return 提前结束。
printScore(120);
}
// void 表示这个方法不返回结果。
public static void printWelcome() {
System.out.println("欢迎进入 Java 方法学习");
}
// String name 是形式参数(形参),只在 greet 方法中有效。
public static void greet(String name) {
System.out.println("你好," + name);
}
// 方法声明返回 int,因此必须返回兼容的整数结果。
public static int add(int a, int b) {
return a + b;
}
// 参数是 int,但除数写成 3.0,计算结果会得到 double。
public static double calculateAverage(int first, int second, int third) {
return (first + second + third) / 3.0;
}
// 比较表达式 age >= 18 的结果本身就是 boolean。
public static boolean isAdult(int age) {
return age >= 18;
}
// && 具有短路特性:name 为 null 时不会执行右侧方法。
public static boolean isUsableName(String name) {
return name != null && !name.isBlank();
}
public static void printScore(int score) {
// 无效输入时提前结束方法,避免继续处理错误数据。
if (score < 0 || score > 100) {
System.out.println("分数无效:" + score);
return;
}
System.out.println("有效分数:" + score);
}
}
阅读顺序:程序从 main 开始;每遇到一次方法调用便跳到对应方法;遇到 return 后携带结果返回调用处。isUsableName(null) 是短路保护的关键案例。
13.2 MethodOverloadDemo.java 完整源码
public class MethodOverloadDemo {
public static void main(String[] args) {
// 两个 int 实参匹配 add(int, int)。
System.out.println(add(10, 20));
// 两个 double 实参匹配 add(double, double)。
System.out.println(add(1.5, 2.5));
// 三个 int 实参匹配 add(int, int, int)。
System.out.println(add(1, 2, 3));
}
public static int add(int a, int b) {
return a + b;
}
public static double add(double a, double b) {
return a + b;
}
public static int add(int a, int b, int c) {
return a + b + c;
}
}
三个方法都叫 add,但参数列表不同。Java 在编译期根据实参的数量和类型选择版本,返回值不参与重载选择。
13.3 StudyPlanMethods.java 完整源码
import java.util.Scanner;
public class StudyPlanMethods {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入姓名:");
String name = scanner.nextLine();
System.out.print("请输入每周学习天数:");
int daysPerWeek = scanner.nextInt();
System.out.print("请输入每天学习小时数:");
double hoursPerDay = scanner.nextDouble();
if (!isValidPlan(daysPerWeek, hoursPerDay)) {
System.out.println("学习计划输入无效。");
scanner.close();
return;
}
double weeklyHours = calculateWeeklyHours(daysPerWeek, hoursPerDay);
String level = getStudyLevel(weeklyHours);
printStudyPlan(name, weeklyHours, level);
scanner.close();
}
public static boolean isValidPlan(int daysPerWeek, double hoursPerDay) {
return daysPerWeek >= 1
&& daysPerWeek <= 7
&& hoursPerDay > 0
&& hoursPerDay <= 24;
}
public static double calculateWeeklyHours(int daysPerWeek, double hoursPerDay) {
return daysPerWeek * hoursPerDay;
}
public static String getStudyLevel(double weeklyHours) {
if (weeklyHours >= 20) {
return "高强度";
} else if (weeklyHours >= 10) {
return "稳定推进";
} else {
return "轻量学习";
}
}
public static void printStudyPlan(String name, double weeklyHours, String level) {
System.out.println();
System.out.println("===== Java 学习计划 =====");
System.out.println("姓名:" + name);
System.out.println("每周学习:" + weeklyHours + " 小时");
System.out.println("学习强度:" + level);
}
}
这里的设计重点是“单一职责”:校验、计算、判断等级、输出各由一个方法负责。将来写后端项目时,控制器、服务和数据访问层也是同样的拆分思想。