第 05 课:方法、参数、返回值、重载与作用域

3 阅读8分钟

第 05 课:方法、参数、返回值、重载与作用域

本课目标

学完后,你应该能够:

  1. 看懂并写出一个 Java 方法。
  2. 区分参数、实参、返回值和 void
  3. 使用 return 返回结果或提前结束方法。
  4. 理解局部变量的作用域。
  5. 理解方法重载的判断规则。
  6. 用方法拆分程序,避免所有逻辑都塞进 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 方法;
  • 带参数的方法;
  • 返回 intdoubleboolean 的方法;
  • 使用 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. 检查题与答案

问题

  1. void 表示什么?
  2. 形参和实参有什么区别?
  3. 返回类型为 int 的方法能否不写 return
  4. return 执行后,方法后面的语句还会执行吗?
  5. add(int, int)add(double, double) 是否构成重载?
  6. 只改变返回值类型能否构成方法重载?
  7. 为什么 name != null && !name.isBlank() 不会在 namenull 时产生空指针?
  8. if 代码块内部声明的变量,离开代码块后还能使用吗?

答案

  1. 方法不向调用者返回结果。
  2. 形参写在方法定义中,是接收数据的变量;实参写在调用处,是实际传入的值。
  3. 正常情况下不能。所有可能正常结束的路径都必须返回兼容的 int 值;否则编译失败。
  4. 不会。return 会立即结束当前方法。
  5. 构成重载,因为参数类型不同。
  6. 不能。重载依据方法名和参数列表,不依据返回值。
  7. && 左侧为 false 后发生短路,右侧方法调用不会执行。
  8. 不能,因为变量已经离开其作用域。

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);
    }
}

这里的设计重点是“单一职责”:校验、计算、判断等级、输出各由一个方法负责。将来写后端项目时,控制器、服务和数据访问层也是同样的拆分思想。