Java 完全指南 / 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();
}
}
⚠️ 注意事项
- 方法名应使用动词或动词短语 —
getName()、calculateTotal()、isValid()。 - 方法不宜过长 — 一个方法超过 30 行就应该考虑拆分。
- 避免过多参数 — 超过 3-4 个参数考虑使用对象封装。
- 递归深度 — JVM 默认栈约 512KB~1MB,深度超过几千层会栈溢出。
- static 方法无法被子类重写 — 可以被隐藏(hide),但不是多态。
💡 技巧
方法链式调用 — 返回
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();工具类设计 — 构造器私有化,防止实例化:
public final class MathUtils { private MathUtils() {} // 阻止实例化 public static int max(int a, int b) { return Math.max(a, b); } }早期返回简化逻辑 — 用 guard clause 替代深层嵌套。
🏢 业务场景
- 工具类:
Math、Arrays、Collections等都大量使用 static 方法。 - 工厂方法:
List.of()、Integer.valueOf()是典型的静态工厂方法。 - 递归应用: 文件系统遍历、树形结构处理、分形算法。
- 方法重载: 提供多种参数形式的 API,如
Collections.sort(list)和Collections.sort(list, comparator)。