Skip to content

第5课:方法

🎯 学习目标

  • 掌握方法的定义和调用
  • 理解参数传递机制
  • 掌握方法重载
  • 理解递归
  • 掌握可变参数

📖 一、方法基础

C vs Java 方法

C 语言

c
// C: 函数
int add(int a, int b) {
    return a + b;
}

Java

java
// Java: 方法(必须在类中)
public class Calculator {
    public static int add(int a, int b) {
        return a + b;
    }
}

1. 方法定义

java
// 语法
修饰符 返回类型 方法名(参数列表) {
    方法体;
    return 返回值;  // 如果有返回值
}

// 示例
public static int add(int a, int b) {
    return a + b;
}

// 无返回值
public static void printMessage(String msg) {
    System.out.println(msg);
}

2. 方法调用

java
public class MethodDemo {
    public static void main(String[] args) {
        // 调用有返回值的方法
        int sum = add(10, 20);
        System.out.println(sum);  // 30
        
        // 调用无返回值的方法
        printMessage("Hello");
    }
    
    public static int add(int a, int b) {
        return a + b;
    }
    
    public static void printMessage(String msg) {
        System.out.println(msg);
    }
}

📖 二、参数传递

1. 基本类型参数(值传递)

java
public class ParamTest {
    public static void main(String[] args) {
        int x = 10;
        change(x);
        System.out.println(x);  // 10(不变)
    }
    
    public static void change(int a) {
        a = 20;  // 只改变副本
    }
}

原理:传递的是值的副本,修改副本不影响原值

2. 引用类型参数(引用传递)

java
public class ParamTest {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        change(arr);
        System.out.println(arr[0]);  // 100(改变了)
    }
    
    public static void change(int[] array) {
        array[0] = 100;  // 修改的是同一个对象
    }
}

原理:传递的是引用的副本,但指向同一个对象

3. String 的特殊性

java
public static void main(String[] args) {
    String str = "Hello";
    change(str);
    System.out.println(str);  // "Hello"(不变)
}

public static void change(String s) {
    s = "World";  // String 不可变
}

📖 三、方法重载

1. 重载规则

java
public class Calculator {
    // 方法1:两个 int 参数
    public static int add(int a, int b) {
        return a + b;
    }
    
    // 方法2:三个 int 参数
    public static int add(int a, int b, int c) {
        return a + b + c;
    }
    
    // 方法3:两个 double 参数
    public static double add(double a, double b) {
        return a + b;
    }
    
    // 使用
    public static void main(String[] args) {
        System.out.println(add(1, 2));        // 3
        System.out.println(add(1, 2, 3));     // 6
        System.out.println(add(1.5, 2.5));    // 4.0
    }
}

重载条件

  • ✅ 方法名相同
  • ✅ 参数列表不同(个数、类型或顺序)
  • ❌ 返回类型不同不算重载
java
// ❌ 编译错误:不算重载
public static int method() { return 1; }
public static double method() { return 1.0; }  // 错误

2. 重载的自动类型转换

java
public class Test {
    public static void method(int x) {
        System.out.println("int: " + x);
    }
    
    public static void method(double x) {
        System.out.println("double: " + x);
    }
    
    public static void main(String[] args) {
        method(10);      // int: 10
        method(10.5);    // double: 10.5
        byte b = 5;
        method(b);       // int: 5(byte 自动转 int)
    }
}

📖 四、递归

1. 递归基础

java
// 阶乘:n! = n × (n-1)!
public static int factorial(int n) {
    if (n == 1) {  // 递归出口
        return 1;
    }
    return n * factorial(n - 1);  // 递归调用
}

// 使用
int result = factorial(5);  // 120

执行过程

factorial(5)
= 5 * factorial(4)
= 5 * (4 * factorial(3))
= 5 * (4 * (3 * factorial(2)))
= 5 * (4 * (3 * (2 * factorial(1))))
= 5 * (4 * (3 * (2 * 1)))
= 120

2. 斐波那契数列

java
// Fibonacci: 1, 1, 2, 3, 5, 8, 13...
public static int fibonacci(int n) {
    if (n == 1 || n == 2) {
        return 1;
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}

3. 递归 vs 循环

java
// 递归实现
public static int sumRecursive(int n) {
    if (n == 1) return 1;
    return n + sumRecursive(n - 1);
}

// 循环实现
public static int sumIterative(int n) {
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        sum += i;
    }
    return sum;
}

对比

  • 递归:代码简洁,但可能栈溢出,性能较低
  • 循环:性能好,不会栈溢出,但代码可能复杂

📖 五、可变参数

1. 基本使用

java
public static int sum(int... numbers) {
    int total = 0;
    for (int num : numbers) {
        total += num;
    }
    return total;
}

// 调用
System.out.println(sum(1, 2, 3));        // 6
System.out.println(sum(1, 2, 3, 4, 5));  // 15
System.out.println(sum());               // 0

2. 可变参数规则

java
// ✅ 可变参数必须是最后一个参数
public static void method(String name, int... scores) { }

// ❌ 错误:可变参数不是最后一个
public static void method(int... scores, String name) { }

// ❌ 错误:只能有一个可变参数
public static void method(int... a, double... b) { }

3. 可变参数的本质

java
// 可变参数本质上是数组
public static void print(int... numbers) {
    System.out.println(numbers.length);  // 数组长度
    for (int num : numbers) {
        System.out.println(num);
    }
}

// 等价于
public static void print(int[] numbers) { }

📖 六、return 语句

1. 返回值

java
public static int max(int a, int b) {
    if (a > b) {
        return a;
    }
    return b;
}

2. 提前返回

java
public static void printPositive(int num) {
    if (num <= 0) {
        return;  // 提前退出
    }
    System.out.println(num);
}

3. 多个 return

java
public static String grade(int score) {
    if (score >= 90) return "A";
    if (score >= 80) return "B";
    if (score >= 70) return "C";
    if (score >= 60) return "D";
    return "F";
}

⚠️ 常见陷阱

陷阱1:方法过长

一个方法承担太多职责,会让测试、复用和排查都变困难。方法应围绕一个清晰动作组织。

陷阱2:重载过度

重载方法太多时,调用者很难判断实际调用哪个版本。参数含义接近时可以考虑对象参数。

陷阱3:递归没有出口

递归必须有明确终止条件,否则会导致 StackOverflowError

陷阱4:可变参数滥用

可变参数适合数量不固定的同类参数,不适合替代结构清晰的参数对象。


🆚 Java vs C 对比

特性C 函数Java 方法
所属关系顶层函数必须属于类或对象
重载不支持支持按参数列表重载
参数传递值传递,指针可改外部对象永远值传递,引用值可指向对象
可变参数stdarg.hT... args

对 C 程序员来说,Java 方法没有“按引用传参”。对象参数传入的是引用值的副本,因此可以改对象内容,但不能让调用者变量指向新对象。


💡 最佳实践

1. 方法应该短小

java
// ❌ 不好:方法太长
public static void processUser() {
    // 100行代码...
}

// ✅ 好:拆分为小方法
public static void processUser() {
    validateUser();
    saveUser();
    sendEmail();
}

2. 方法只做一件事

java
// ❌ 不好:做了多件事
public static void processAndSave(User user) {
    validate(user);
    save(user);
    log(user);
}

// ✅ 好:每个方法只做一件事
public static void validateUser(User user) { }
public static void saveUser(User user) { }
public static void logUser(User user) { }

3. 避免过深的递归

java
// ❌ 可能栈溢出
factorial(10000);

// ✅ 改用循环

📝 练习

完成 练习/Ex05_Methods.java

  1. 方法定义和调用
  2. 参数传递测试
  3. 方法重载
  4. 递归实现
  5. 可变参数
  6. 综合:数学工具类

🎓 下一步

  • 第7课:继承 - extends、super、方法重写