强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

07 - 方法:重载、可变参数、递归、static

07 - 方法:重载、可变参数、递归、static

方法定义

[修饰符] 返回类型 方法名([参数列表]) [throws 异常列表] {
    // 方法体
    [return 返回值;]
}
public class MethodBasics {
    // 无返回值、无参数
    public static void sayHello() {
        System.out.println("Hello!");
    }

    // 有返回值
    public static int add(int a, int b) {
        return a + b;
    }

    // 无返回值、有参数
    public static void printInfo(String name, int age) {
        System.out.println(name + ", " + age + "岁");
    }

    public static void main(String[] args) {
        sayHello();                      // Hello!
        int result = add(3, 5);          // result = 8
        printInfo("张三", 25);           // 张三, 25岁
    }
}

参数传递

Java 中只有值传递(pass by value):

public class PassByValueDemo {
    // 基本类型:传递值的拷贝
    static void modifyInt(int x) {
        x = 100;  // 不影响原始变量
    }

    // 引用类型:传递引用的拷贝
    static void modifyArray(int[] arr) {
        arr[0] = 100;  // ✅ 修改数组内容,影响原数组
    }

    // 引用类型:重新赋值不影响原始引用
    static void reassignArray(int[] arr) {
        arr = new int[]{100, 200};  // ❌ 不影响原数组
    }

    // 引用类型:修改对象属性
    static void modifyPerson(Person p) {
        p.name = "李四";  // ✅ 修改属性,影响原对象
    }

    static class Person {
        String name;
        Person(String name) { this.name = name; }
    }

    public static void main(String[] args) {
        int x = 10;
        modifyInt(x);
        System.out.println("x = " + x);  // 10(未改变)

        int[] arr = {1, 2, 3};
        modifyArray(arr);
        System.out.println("arr[0] = " + arr[0]);  // 100(已改变)

        reassignArray(arr);
        System.out.println("arr[0] = " + arr[0]);  // 100(未变,因为 reassign 后 arr 指向新数组)

        Person p = new Person("张三");
        modifyPerson(p);
        System.out.println("name = " + p.name);  // 李四(已改变)
    }
}

方法重载(Overloading)

同一个类中,方法名相同但参数列表不同:

public class OverloadDemo {
    // 参数类型不同
    static int add(int a, int b) {
        System.out.println("int 版本");
        return a + b;
    }

    static double add(double a, double b) {
        System.out.println("double 版本");
        return a + b;
    }

    // 参数个数不同
    static int add(int a, int b, int c) {
        return a + b + c;
    }

    // 参数顺序不同
    static void show(String name, int age) {
        System.out.println(name + ", " + age);
    }

    static void show(int age, String name) {
        System.out.println(age + ", " + name);
    }

    public static void main(String[] args) {
        System.out.println(add(1, 2));         // int 版本 → 3
        System.out.println(add(1.0, 2.0));     // double 版本 → 3.0
        System.out.println(add(1, 2, 3));      // 6
        show("张三", 25);                       // 张三, 25
        show(25, "张三");                       // 25, 张三
    }
}

重载解析规则

优先级规则示例
1精确匹配add(int, int)
2自动拓宽add(long, long) 接受 int
3自动装箱add(Integer, Integer)
4可变参数add(int...)

可变参数(Varargs)

public class VarargsDemo {
    // 基本可变参数
    static int sum(int... numbers) {
        int total = 0;
        for (int n : numbers) {
            total += n;
        }
        return total;
    }

    // 可变参数必须是最后一个参数
    static void printInfo(String prefix, String... items) {
        System.out.print(prefix + ": ");
        for (String item : items) {
            System.out.print(item + " ");
        }
        System.out.println();
    }

    // 可变参数数组
    static <T> List<T> asList(T... elements) {
        List<T> list = new ArrayList<>();
        for (T e : elements) {
            list.add(e);
        }
        return list;
    }

    public static void main(String[] args) {
        System.out.println(sum());              // 0
        System.out.println(sum(1, 2));          // 3
        System.out.println(sum(1, 2, 3, 4, 5)); // 15

        // 传数组给可变参数
        int[] arr = {10, 20, 30};
        System.out.println(sum(arr));            // 60

        printInfo("水果", "苹果", "香蕉", "橘子");
        printInfo("城市");  // 城市:

        List<String> list = asList("A", "B", "C");
        System.out.println(list);  // [A, B, C]
    }
}

递归(Recursion)

public class RecursionDemo {
    // 阶乘: n! = n × (n-1)!
    static long factorial(int n) {
        if (n <= 1) return 1;        // 递归终止条件(base case)
        return n * factorial(n - 1);  // 递归调用
    }

    // 斐波那契数列: f(n) = f(n-1) + f(n-2)
    static long fibonacci(int n) {
        if (n <= 1) return n;
        return fibonacci(n - 1) + fibonacci(n - 2);
    }

    // 带记忆化的斐波那契(优化)
    static long[] memo = new long[100];
    static long fibMemo(int n) {
        if (n <= 1) return n;
        if (memo[n] != 0) return memo[n];
        memo[n] = fibMemo(n - 1) + fibMemo(n - 2);
        return memo[n];
    }

    // 递归遍历目录
    static void listFiles(java.io.File dir, String indent) {
        java.io.File[] files = dir.listFiles();
        if (files == null) return;
        for (java.io.File f : files) {
            System.out.println(indent + (f.isDirectory() ? "📁 " : "📄 ") + f.getName());
            if (f.isDirectory()) {
                listFiles(f, indent + "  ");
            }
        }
    }

    // 汉诺塔
    static void hanoi(int n, char from, char to, char aux) {
        if (n == 1) {
            System.out.printf("移动盘子 1 从 %c 到 %c%n", from, to);
            return;
        }
        hanoi(n - 1, from, aux, to);
        System.out.printf("移动盘子 %d 从 %c 到 %c%n", n, from, to);
        hanoi(n - 1, aux, to, from);
    }

    public static void main(String[] args) {
        System.out.println("5! = " + factorial(5));     // 120
        System.out.println("fib(10) = " + fibMemo(10)); // 55
        hanoi(3, 'A', 'C', 'B');
    }
}

⚠️ 递归必须有终止条件,否则会 StackOverflowError。对于深度较大的递归,考虑改为迭代或尾递归优化。

static 关键字

public class StaticDemo {
    // 静态变量(类变量)—— 所有实例共享
    static int instanceCount = 0;

    // 实例变量
    String name;

    // 构造器
    StaticDemo(String name) {
        this.name = name;
        instanceCount++;
    }

    // 静态方法 —— 不依赖实例,用类名调用
    static int getCount() {
        return instanceCount;
    }

    // 静态代码块 —— 类加载时执行一次
    static {
        System.out.println("StaticDemo 类被加载了!");
    }

    // 实例方法 —— 依赖实例
    void sayHello() {
        System.out.println("我是 " + name);
    }

    // 静态内部类
    static class Inner {
        void show() {
            System.out.println("静态内部类,可访问静态成员: " + instanceCount);
        }
    }

    public static void main(String[] args) {
        System.out.println("初始实例数: " + getCount());  // 0

        new StaticDemo("张三");
        new StaticDemo("李四");
        new StaticDemo("王五");

        System.out.println("当前实例数: " + getCount());  // 3

        StaticDemo.Inner inner = new StaticDemo.Inner();
        inner.show();
    }
}

static 成员 vs 实例成员对比

维度static 成员实例成员
属于类本身对象实例
调用方式ClassName.method()obj.method()
内存方法区/元空间,只有一份堆内存,每个对象一份
访问不能访问实例成员可以访问静态和实例成员
this不能使用 this可以使用 this
生命周期类加载 → 类卸载对象创建 → GC

⚠️ static 方法中不能直接调用实例方法或访问实例变量,因为没有 this 引用。

方法引用(JDK 8+,提前了解)

import java.util.*;
import java.util.function.*;

public class MethodRefDemo {
    public static void main(String[] args) {
        // 静态方法引用: ClassName::staticMethod
        Function<String, Integer> parser = Integer::parseInt;
        System.out.println(parser.apply("42"));  // 42

        // 实例方法引用: instance::method
        String str = "Hello";
        Supplier<Integer> lenSupplier = str::length;
        System.out.println(lenSupplier.get());  // 5

        // 任意对象方法引用: ClassName::instanceMethod
        Function<String, String> upper = String::toUpperCase;
        System.out.println(upper.apply("hello"));  // HELLO

        // 构造器引用: ClassName::new
        Supplier<ArrayList<String>> listFactory = ArrayList::new;
        List<String> list = listFactory.get();
    }
}

⚠️ 注意事项

  1. 方法名应使用动词或动词短语getName()calculateTotal()isValid()
  2. 方法不宜过长 — 一个方法超过 30 行就应该考虑拆分。
  3. 避免过多参数 — 超过 3-4 个参数考虑使用对象封装。
  4. 递归深度 — JVM 默认栈约 512KB~1MB,深度超过几千层会栈溢出。
  5. static 方法无法被子类重写 — 可以被隐藏(hide),但不是多态。

💡 技巧

  1. 方法链式调用 — 返回 this 实现 Builder 模式:

    public class QueryBuilder {
        private String table;
        private String condition;
        public QueryBuilder from(String table) { this.table = table; return this; }
        public QueryBuilder where(String cond) { this.condition = cond; return this; }
        public String build() { return "SELECT * FROM " + table + " WHERE " + condition; }
    }
    // 使用: new QueryBuilder().from("users").where("age > 18").build();
    
  2. 工具类设计 — 构造器私有化,防止实例化:

    public final class MathUtils {
        private MathUtils() {} // 阻止实例化
        public static int max(int a, int b) { return Math.max(a, b); }
    }
    
  3. 早期返回简化逻辑 — 用 guard clause 替代深层嵌套。

🏢 业务场景

  • 工具类: MathArraysCollections 等都大量使用 static 方法。
  • 工厂方法: List.of()Integer.valueOf() 是典型的静态工厂方法。
  • 递归应用: 文件系统遍历、树形结构处理、分形算法。
  • 方法重载: 提供多种参数形式的 API,如 Collections.sort(list)Collections.sort(list, comparator)

📖 扩展阅读