Java 方法
当你在多处写同样的代码,就该把它抽成方法(Function/Method)。方法是"代码复用"的基本单元——给它输入,它返回输出。本章带你掌握 Java 方法的定义、调用、参数传递、重载、可变参数和递归。
1. 方法定义与调用
Java 方法定义的格式:修饰符 返回类型 方法名(参数列表) { 方法体 }。所有方法必须定义在类内部。
public class MethodDemo {
// 方法定义格式:
// 修饰符 返回类型 方法名(参数列表) { 方法体 }
public static int add(int a, int b) {
return a + b; // 返回 int
}
// 无返回值用 void,不需要 return
public static void greet(String name) {
System.out.println("你好, " + name);
}
// 无参数
public static String getVersion() {
return "v1.0";
}
public static void main(String[] args) {
int sum = add(3, 5); // 调用并接收返回值
System.out.println(sum); // 8
greet("小明"); // 调用 void 方法,不接返回值
System.out.println(getVersion()); // v1.0
}
}方法签名的几个组成:
- 修饰符:
public/private/protected控制访问范围;static表示静态方法。 - 返回类型:方法计算结果的类型。无返回值用
void;有返回值则用return返回。 - 方法名:小驼峰命名,动词开头更清晰(
getUserName、printReport)。 - 参数列表:接收的输入。多个用逗号隔开。无参数也要写
()。
2. Java 是"值传递"!理解参数传递
这是新手最容易迷糊的概念。Java 只有值传递——但"值"对基本类型和引用类型含义不同:
- 基本类型:传值的副本,方法内修改不影响外部。
- 引用类型:传地址的副本,但地址指向同一个对象——所以通过它可以改对象内部,但替换整个引用不影响外部。
public class PassByValue {
// 1. 基本类型:传值的副本,方法内改不影响外部
public static void doubleIt(int x) {
x = x * 2;
System.out.println("方法内 x = " + x);
}
// 2. 引用类型:传地址的副本,通过它可以改对象内部
public static void addOne(int[] arr) {
arr[0] = arr[0] + 1;
}
public static void main(String[] args) {
int n = 10;
doubleIt(n);
System.out.println("方法外 n = " + n); // 10(不变)
int[] data = {1, 2, 3};
addOne(data);
System.out.println(data[0]); // 2(被改了!)
}
}3. 方法重载(Overload)
同一个类中可以定义同名但参数列表不同的多个方法,叫"重载"。编译器根据你传的参数类型/个数,自动决定调用哪个版本。
public class OverloadDemo {
// 方法重载(Overload):同名、参数列表不同(个数/类型/顺序)
// 返回类型不同不算重载,会编译报错
public static int max(int a, int b) {
return a > b ? a : b;
}
public static double max(double a, double b) {
return a > b ? a : b;
}
public static int max(int a, int b, int c) {
return max(max(a, b), c);
}
public static void main(String[] args) {
System.out.println(max(3, 5)); // 5 调用 int 版
System.out.println(max(3.5, 2.7)); // 3.5 调用 double 版
System.out.println(max(3, 9, 5)); // 9 调用三参数版
}
}重载的好处:同一概念用同一名字,API 更简洁——如 System.out.println(int) / println(String) / println(double) 都是重载。注意:返回类型不同不算重载,参数列表必须不同。
4. 可变参数(int...)
有时候你想让方法接收任意多个参数(如 sum(1,2,3) 或 sum(1,2,3,4,5)),用可变参数(varargs):
public class VarArgsDemo {
// 可变参数:类型... 参数名,本质是数组
// 调用时可以传 0~N 个参数,也可以直接传数组
public static int sum(int... nums) {
int total = 0;
for (int n : nums) {
total += n;
}
return total;
}
// 可变参数必须放参数列表最后,且一个方法只能有一个可变参数
public static String join(String sep, String... parts) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < parts.length; i++) {
if (i > 0) sb.append(sep);
sb.append(parts[i]);
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(sum(1, 2, 3)); // 6
System.out.println(sum(1, 2, 3, 4, 5)); // 15
System.out.println(sum()); // 0(空参也行)
int[] arr = {10, 20, 30};
System.out.println(sum(arr)); // 60(直接传数组)
System.out.println(join(", ", "a", "b", "c")); // a, b, c
}
}可变参数的本质是数组——int... nums 在方法内就是 int[]。规则:
- 必须放参数列表最后。
- 一个方法最多一个可变参数。
- 可以传 0 个参数,也可以直接传数组。
5. 递归(方法调用自己)
递归是"方法调用自己"的技巧,适合分治问题(阶乘、斐波那契、树/图遍历、回溯)。两个关键:
- 终止条件(递归出口):否则无限递归导致
StackOverflowError(栈溢出)。 - 递归调用:每次调用规模要更小,逐步逼近终止条件。
public class RecursionDemo {
// 递归:方法调用自己,必须有"终止条件",否则栈溢出
public static int factorial(int n) {
if (n <= 1) return 1; // 终止条件(递归出口)
return n * factorial(n - 1); // 递归调用
}
// 经典:斐波那契数列 F(n) = F(n-1) + F(n-2)
public static int fib(int n) {
if (n < 2) return n;
return fib(n - 1) + fib(n - 2);
}
public static void main(String[] args) {
System.out.println(factorial(5)); // 120 (5! = 5*4*3*2*1)
System.out.println(fib(10)); // 55
// ⚠️ 递归太深会 StackOverflowError
// factorial(100000); // ❌ 栈溢出
}
}递归虽优雅但有性能开销:每次调用都要压栈,深度过大会栈溢出。fib(40) 这种朴素递归会重复计算,效率极低——实际工程中常用循环或记忆化替代。
6. 静态方法(static)
用 static 修饰的方法属于类本身,不需要创建对象就能直接调用:类名.方法名()。Math 类的所有方法都是静态的。
public class StaticMethod {
// 静态方法(类方法):用 static 修饰,属于类,直接用 类名.方法() 调用
public static double circleArea(double r) {
return Math.PI * r * r;
}
public static void main(String[] args) {
// 调用静态方法:可以 类名.方法(),同类中可以省略类名
double area = StaticMethod.circleArea(2.0);
System.out.println(area); // 12.566...
// Math 类全是静态方法,这是经典例子
System.out.println(Math.max(3, 5)); // 5
System.out.println(Math.abs(-10)); // 10
System.out.println(Math.sqrt(16)); // 4.0
}
}静态方法 vs 实例方法:
- 静态方法:属于类,所有对象共享,不能访问实例变量(没有
this)。 - 实例方法:属于对象,必须
new出对象才能调用,可以访问实例变量。 - 工具方法(纯计算,不依赖对象状态)优先静态化(如
Math.max)。
7. 方法的最佳实践
- 单一职责:一个方法只做一件事,几十行的小方法优于几百行的大方法。
- 命名清晰:看名字就知道做什么(
calculateTax()>calc())。 - 参数不要太多:超过 4~5 个就考虑封装成对象。
- 避免副作用:理想的方法接收输入、返回输出,不改外部状态。
- 及时 return:少用嵌套 if-else,用"提前 return"让逻辑更扁平。
小结
这一章你掌握了 Java 方法的全部要点:定义、调用、值传递、重载、可变参数、递归、静态方法。下一篇我们看 Java 数组——存一组同类型数据的容器,是后面学集合的基础。
← 上一篇 Java 流程控制
下一篇 Java 数组 →