Skip to content

方法

方法是完成特定功能的代码块,是 Java 程序的基本组成单元。方法可以提高代码的复用性和可维护性。

方法的定义

基本语法

text
修饰符 返回值类型 方法名(参数列表) {
    方法体
    return 返回值;
}

方法定义示例

java
public class MethodDefinition {
    public static void main(String[] args) {
        // 调用方法
        int result = add(10, 20);
        System.out.println("10 + 20 = " + result);
        
        printHello();
        greet("张三");
    }
    
    /**
     * 定义一个加法方法
     * @param a 第一个加数
     * @param b 第二个加数
     * @return 两数之和
     */
    public static int add(int a, int b) {
        int sum = a + b;
        return sum;  // 返回计算结果
    }
    
    /**
     * 无参数无返回值的方法
     */
    public static void printHello() {
        System.out.println("Hello, Java!");
    }
    
    /**
     * 有参数无返回值的方法
     * @param name 姓名
     */
    public static void greet(String name) {
        System.out.println("你好," + name + "!");
    }
}

方法组成部分

java
public class MethodComponents {
    // public static:修饰符
    // int:返回值类型
    // calculate:方法名
    // int a, int b:参数列表
    public static int calculate(int a, int b) {
        // 方法体
        int result = a * b + 100;
        
        // return:返回语句
        return result;
    }
    
    // 无返回值的方法使用 void
    public static void showMessage(String message) {
        System.out.println("消息:" + message);
        // void 方法可以没有 return,或者只写 return;
        return;  // 可选
    }
}

方法的调用

调用方式

java
public class MethodCall {
    public static void main(String[] args) {
        // 直接调用
        printInfo();
        
        // 赋值调用(有返回值的方法)
        int max = getMax(10, 20);
        System.out.println("最大值: " + max);
        
        // 输出调用
        System.out.println("最小值: " + getMin(10, 20));
        
        // 表达式中调用
        int result = getMax(5, 8) * 2 + getMin(3, 7);
        System.out.println("计算结果: " + result);
        
        // 嵌套调用
        int nested = getMax(getMax(1, 2), getMax(3, 4));
        System.out.println("嵌套调用结果: " + nested);
    }
    
    public static void printInfo() {
        System.out.println("这是一个无返回值的方法");
    }
    
    public static int getMax(int a, int b) {
        return a > b ? a : b;
    }
    
    public static int getMin(int a, int b) {
        return a < b ? a : b;
    }
}

调用其他类的方法

java
// 定义一个工具类
class MathUtils {
    // 静态方法:通过类名调用
    public static int square(int n) {
        return n * n;
    }
    
    // 实例方法:需要创建对象调用
    public int cube(int n) {
        return n * n * n;
    }
}

public class CallOtherClass {
    public static void main(String[] args) {
        // 调用静态方法:类名.方法名
        int sq = MathUtils.square(5);
        System.out.println("5的平方: " + sq);
        
        // 调用实例方法:对象.方法名
        MathUtils utils = new MathUtils();
        int cb = utils.cube(3);
        System.out.println("3的立方: " + cb);
    }
}

参数传递

基本类型参数

基本类型参数是值传递,方法内修改不影响原值。

java
public class PrimitiveParam {
    public static void main(String[] args) {
        int num = 10;
        System.out.println("调用前: num = " + num);  // 10
        
        changeValue(num);
        System.out.println("调用后: num = " + num);  // 10(值不变)
    }
    
    public static void changeValue(int n) {
        n = 100;  // 修改的是副本,不影响原值
        System.out.println("方法内: n = " + n);  // 100
    }
}

引用类型参数

引用类型参数传递的是地址,方法内修改会影响原对象。

java
public class ReferenceParam {
    public static void main(String[] args) {
        // 数组是引用类型
        int[] arr = {1, 2, 3};
        System.out.println("调用前: " + java.util.Arrays.toString(arr));  // [1, 2, 3]
        
        modifyArray(arr);
        System.out.println("调用后: " + java.util.Arrays.toString(arr));  // [100, 2, 3]
        
        // 对象也是引用类型
        Person person = new Person();
        person.name = "张三";
        System.out.println("调用前: " + person.name);  // 张三
        
        modifyPerson(person);
        System.out.println("调用后: " + person.name);  // 李四
    }
    
    public static void modifyArray(int[] array) {
        array[0] = 100;  // 修改数组元素,影响原数组
    }
    
    public static void modifyPerson(Person p) {
        p.name = "李四";  // 修改对象属性,影响原对象
    }
}

class Person {
    String name;
}

可变参数

Java 支持可变参数,允许传递任意数量的同类型参数。

java
public class VarargsDemo {
    public static void main(String[] args) {
        // 传递多个参数
        int sum1 = sum(1, 2, 3);
        System.out.println("sum(1, 2, 3) = " + sum1);  // 6
        
        // 传递数组
        int[] arr = {1, 2, 3, 4, 5};
        int sum2 = sum(arr);
        System.out.println("sum(arr) = " + sum2);  // 15
        
        // 不传参数
        int sum3 = sum();
        System.out.println("sum() = " + sum3);  // 0
        
        // 可变参数与普通参数混用
        printInfo("学生", 90, 85, 95);
    }
    
    /**
     * 可变参数方法
     * @param numbers 可变参数,本质是数组
     * @return 所有参数的和
     */
    public static int sum(int... numbers) {
        int total = 0;
        for (int num : numbers) {
            total += num;
        }
        return total;
    }
    
    /**
     * 可变参数必须放在参数列表最后
     * @param name 姓名
     * @param scores 成绩(可变参数)
     */
    public static void printInfo(String name, int... scores) {
        System.out.print(name + " 的成绩:");
        for (int score : scores) {
            System.out.print(score + " ");
        }
        System.out.println();
    }
}

方法重载

方法重载是指在同一个类中定义多个同名但参数列表不同的方法。

重载规则

text
┌─────────────────────────────────────────────────────────────────┐
│                     方法重载规则                                 │
├─────────────────────────────────────────────────────────────────┤
│  1. 方法名必须相同                                               │
│  2. 参数列表必须不同(参数个数、类型、顺序)                      │
│  3. 返回值类型可以相同也可以不同                                 │
│  4. 与访问修饰符无关                                             │
└─────────────────────────────────────────────────────────────────┘

重载示例

java
public class MethodOverload {
    public static void main(String[] args) {
        // 根据参数类型自动匹配方法
        System.out.println("add(10, 20) = " + add(10, 20));          // int
        System.out.println("add(10.5, 20.5) = " + add(10.5, 20.5));  // double
        System.out.println("add(10, 20, 30) = " + add(10, 20, 30));  // 三个参数
    }
    
    // 两个 int 参数
    public static int add(int a, int b) {
        System.out.println("调用 int add(int, int)");
        return a + b;
    }
    
    // 两个 double 参数(参数类型不同)
    public static double add(double a, double b) {
        System.out.println("调用 double add(double, double)");
        return a + b;
    }
    
    // 三个 int 参数(参数个数不同)
    public static int add(int a, int b, int c) {
        System.out.println("调用 int add(int, int, int)");
        return a + b + c;
    }
    
    // 参数顺序不同
    public static void show(int a, String b) {
        System.out.println("int, String: " + a + ", " + b);
    }
    
    public static void show(String a, int b) {
        System.out.println("String, int: " + a + ", " + b);
    }
}

重载与可变参数

java
public class OverloadVarargs {
    public static void main(String[] args) {
        print(1);
        print(1, 2);
        print(1, 2, 3);
    }
    
    // 优先匹配固定参数的方法
    public static void print(int a) {
        System.out.println("一个参数: " + a);
    }
    
    public static void print(int a, int b) {
        System.out.println("两个参数: " + a + ", " + b);
    }
    
    // 可变参数作为后备选项
    public static void print(int... nums) {
        System.out.print("多个参数: ");
        for (int num : nums) {
            System.out.print(num + " ");
        }
        System.out.println();
    }
}

方法递归

递归是方法调用自身的过程,适合解决可以分解为相似子问题的问题。

递归基本结构

java
public class RecursionBasic {
    public static void main(String[] args) {
        // 计算 5 的阶乘
        int result = factorial(5);
        System.out.println("5! = " + result);  // 120
        
        // 计算 1 到 100 的和
        int sum = sumToN(100);
        System.out.println("1到100的和 = " + sum);  // 5050
    }
    
    /**
     * 计算阶乘(递归)
     * n! = n * (n-1)!
     */
    public static int factorial(int n) {
        // 递归终止条件(必须有)
        if (n <= 1) {
            return 1;
        }
        // 递归调用
        return n * factorial(n - 1);
    }
    
    /**
     * 计算 1 到 n 的和(递归)
     */
    public static int sumToN(int n) {
        if (n <= 0) {
            return 0;
        }
        return n + sumToN(n - 1);
    }
}

经典递归案例

java
public class RecursionExamples {
    public static void main(String[] args) {
        // 斐波那契数列
        System.out.println("斐波那契数列前10项:");
        for (int i = 1; i <= 10; i++) {
            System.out.print(fibonacci(i) + " ");
        }
        System.out.println();
        
        // 汉诺塔
        System.out.println("\n汉诺塔(3个盘子):");
        hanoi(3, 'A', 'B', 'C');
        
        // 二分查找(递归)
        int[] arr = {1, 3, 5, 7, 9, 11, 13};
        int index = binarySearch(arr, 7, 0, arr.length - 1);
        System.out.println("\n7 的索引: " + index);
    }
    
    /**
     * 斐波那契数列
     * 1, 1, 2, 3, 5, 8, 13, 21, ...
     */
    public static int fibonacci(int n) {
        if (n <= 2) {
            return 1;
        }
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
    
    /**
     * 汉诺塔问题
     * @param n 盘子数量
     * @param from 起始柱
     * @param aux 辅助柱
     * @param to 目标柱
     */
    public static void hanoi(int n, char from, char aux, char to) {
        if (n == 1) {
            System.out.println("移动盘子 1 从 " + from + " 到 " + to);
            return;
        }
        // 将 n-1 个盘子从 from 移到 aux
        hanoi(n - 1, from, to, aux);
        // 将第 n 个盘子从 from 移到 to
        System.out.println("移动盘子 " + n + " 从 " + from + " 到 " + to);
        // 将 n-1 个盘子从 aux 移到 to
        hanoi(n - 1, aux, from, to);
    }
    
    /**
     * 二分查找(递归版)
     */
    public static int binarySearch(int[] arr, int target, int left, int right) {
        if (left > right) {
            return -1;  // 未找到
        }
        int mid = (left + right) / 2;
        if (arr[mid] == target) {
            return mid;
        } else if (arr[mid] < target) {
            return binarySearch(arr, target, mid + 1, right);
        } else {
            return binarySearch(arr, target, left, mid - 1);
        }
    }
}

递归与循环对比

java
public class RecursionVsLoop {
    public static void main(String[] args) {
        int n = 10;
        
        // 递归方式
        long start1 = System.nanoTime();
        long result1 = factorialRecursive(n);
        long end1 = System.nanoTime();
        System.out.println("递归结果: " + result1 + ", 耗时: " + (end1 - start1) + " ns");
        
        // 循环方式
        long start2 = System.nanoTime();
        long result2 = factorialLoop(n);
        long end2 = System.nanoTime();
        System.out.println("循环结果: " + result2 + ", 耗时: " + (end2 - start2) + " ns");
    }
    
    // 递归方式
    public static long factorialRecursive(int n) {
        if (n <= 1) return 1;
        return n * factorialRecursive(n - 1);
    }
    
    // 循环方式
    public static long factorialLoop(int n) {
        long result = 1;
        for (int i = 2; i <= n; i++) {
            result *= i;
        }
        return result;
    }
}

方法的作用域

局部变量

java
public class MethodScope {
    // 类变量(成员变量)
    private int instanceVar = 10;
    private static int staticVar = 20;
    
    public void method1() {
        // 局部变量:方法内有效
        int localVar = 30;
        System.out.println("局部变量: " + localVar);
        System.out.println("实例变量: " + instanceVar);
        System.out.println("静态变量: " + staticVar);
    }
    
    public void method2() {
        // localVar 在这里不可访问
        // System.out.println(localVar);  // 编译错误
        
        // 可以定义同名局部变量
        int instanceVar = 100;  // 遮蔽了实例变量
        System.out.println("局部 instanceVar: " + instanceVar);  // 100
        System.out.println("实例变量: " + this.instanceVar);      // 10
    }
    
    public void method3(int param) {
        // 参数也是局部变量
        System.out.println("参数: " + param);
        
        // 代码块内的局部变量
        {
            int blockVar = 50;
            System.out.println("块变量: " + blockVar);
        }
        // blockVar 在这里不可访问
        // System.out.println(blockVar);  // 编译错误
    }
}

方法最佳实践

单一职责原则

java
public class MethodBestPractice {
    public static void main(String[] args) {
        // 好的做法:每个方法只做一件事
        int[] numbers = {5, 2, 8, 1, 9};
        
        printArray(numbers);
        sortArray(numbers);
        printArray(numbers);
        int max = findMax(numbers);
        System.out.println("最大值: " + max);
    }
    
    // 好的做法:方法名清晰表达功能
    public static void printArray(int[] arr) {
        System.out.println(java.util.Arrays.toString(arr));
    }
    
    public static void sortArray(int[] arr) {
        java.util.Arrays.sort(arr);
    }
    
    public static int findMax(int[] arr) {
        int max = arr[0];
        for (int num : arr) {
            if (num > max) {
                max = num;
            }
        }
        return max;
    }
    
    // 不好的做法:一个方法做太多事
    // public static void printSortAndFindMax(int[] arr) { ... }
}

参数和返回值设计

java
public class ParameterDesign {
    public static void main(String[] args) {
        // 参数不宜过多(建议不超过 3-4 个)
        // 如果参数太多,考虑使用对象封装
        
        // 好的做法
        User user = new User("张三", 25, "zhangsan@example.com");
        registerUser(user);
        
        // 不好的做法
        // registerUser("张三", 25, "zhangsan@example.com", "13800138000", "北京市", ...);
    }
    
    public static void registerUser(User user) {
        System.out.println("注册用户: " + user.name);
    }
    
    // 返回值要有意义
    // 好的做法:返回操作结果
    public static boolean deleteUser(int userId) {
        // 删除逻辑
        return true;  // 返回是否成功
    }
    
    // 好的做法:返回 null 或 Optional 表示无结果
    public static User findUserById(int userId) {
        // 查找逻辑
        return null;  // 未找到返回 null
    }
}

class User {
    String name;
    int age;
    String email;
    
    public User(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
}

小结

本章我们学习了:

  • 方法定义:修饰符、返回值、方法名、参数列表
  • 方法调用:直接调用、赋值调用、输出调用
  • 参数传递:值传递、引用传递、可变参数
  • 方法重载:同名不同参
  • 方法递归:方法调用自身
  • 最佳实践:单一职责、合理设计参数和返回值

下一章,我们将学习 数组,了解 Java 中数组的使用。