方法、参数、返回值与方法重载 | JavaSE
方法、参数、返回值与方法重载
一、学习目标
完成本章后,你应该能够:
- 能够解释 Java 方法(Method)的作用以及为什么需要方法。
- 能够从零定义并调用无参数、有参数、无返回值和有返回值方法。
- 能够区分形式参数(Formal Parameter)与实际参数(Argument)。
- 能够正确使用
return返回结果或提前结束方法。 - 能够理解方法调用过程中参数变量的基本工作方式。
- 能够解释 Java 参数传递的值传递(Pass by Value)语义。
- 能够判断多个方法是否构成方法重载(Overloading)。
- 能够根据方法名和参数列表判断编译器会选择哪个重载方法。
- 能够把过长的
main方法拆分成职责清晰、可以复用的小方法。
二、核心知识
2.1 什么是方法
方法(Method)是一段:
为完成某个明确功能而组织起来、可以被调用执行的代码。
例如一个程序需要多次求两个整数的最大值。
如果每次都写:
int max = a > b ? a : b;
程序中会出现大量重复逻辑。
我们可以把这个功能封装为方法:
public static int max(int a, int b) {
return a > b ? a : b;
}
以后需要时直接调用:
int result = max(10, 20);
因此可以把方法理解为:
输入数据
↓
方法
↓
处理逻辑
↓
输出结果
方法帮助我们解决几个核心问题:
代码重复
职责混乱
main 方法过长
代码难以测试
代码难以复用
代码难以维护
2.2 为什么需要方法
假设现在需要:
- 计算 10 和 20 的最大值。
- 计算 100 和 200 的最大值。
- 计算用户输入的两个数的最大值。
如果不用方法,就可能反复编写相同代码。
而使用:
public static int max(int a, int b) {
return a > b ? a : b;
}
就可以:
int result1 = max(10, 20);
int result2 = max(100, 200);
int result3 = max(x, y);
所以方法的核心价值可以概括为:
把一个具有明确职责的功能封装起来,并通过调用重复使用。
2.3 方法的基本定义格式
基础阶段可以先掌握:
修饰符 返回值类型 方法名(参数列表) {
方法体;
return 返回值;
}
例如:
public static int add(int a, int b) {
int result = a + b;
return result;
}
拆开:
public static
↓
修饰部分
int
↓
返回值类型
add
↓
方法名
(int a, int b)
↓
参数列表
{
...
}
↓
方法体
当前 Java 基础语法阶段主要使用:
public static
形式的方法。
这里暂时把它作为基础方法定义格式使用。
static 的完整原理会在后续面向对象章节系统学习。
2.4 方法不会因为“定义了”就自动执行
例如:
public class MethodDemo {
public static void main(String[] args) {
System.out.println("main");
}
public static void hello() {
System.out.println("Hello Java");
}
}
程序只会输出:
main
因为:
hello()
虽然已经定义,却没有被调用。
想执行它,需要:
hello();
完整代码:
public class MethodDemo {
public static void main(String[] args) {
System.out.println("开始");
hello();
System.out.println("结束");
}
public static void hello() {
System.out.println("Hello Java");
}
}
执行顺序可以理解为:
main 开始
↓
调用 hello()
↓
进入 hello()
↓
执行 hello 方法体
↓
hello 结束
↓
返回 main
↓
main 继续执行
2.5 无参数、无返回值方法
最简单的方法:
public static void printHello() {
System.out.println("Hello Java");
}
调用:
printHello();
这里:
()
中没有参数。
而:
void
表示:
这个方法正常完成时不向调用者返回一个结果值。
例如:
public static void printLine() {
System.out.println("----------------");
}
适合:
打印内容
执行某个动作
修改某些数据
完成某项操作
而不需要把一个结果交回调用位置的场景。
2.6 有参数方法
如果一个方法需要处理外部传入的数据,可以定义参数:
public static void printAge(int age) {
System.out.println("年龄:" + age);
}
调用:
printAge(22);
执行时可以理解成:
22
↓
传入方法
↓
age = 22
↓
执行方法体
参数让方法从:
只能处理固定数据
升级为:
可以处理不同数据
例如:
printAge(18);
printAge(20);
printAge(22);
使用的是同一个方法,但输入不同。
2.7 形式参数与实际参数
这是必须区分的一组术语。
方法定义:
public static int add(int a, int b) {
return a + b;
}
其中:
int a
int b
叫:
形式参数(Formal Parameter),简称形参。
调用:
int result = add(10, 20);
其中:
10
20
叫实际参数,更准确地说是:
Argument,通常简称实参。
可以理解为:
方法定义:
add(int a, int b)
↑ ↑
形参 形参
方法调用:
add(10, 20)
↑ ↑
实参 实参
形参负责:
声明这个方法需要接收什么数据。
实参负责:
在某一次具体调用时提供真正的数据。
2.8 参数的个数、类型和顺序需要匹配
定义:
public static void show(String name, int age) {
System.out.println(name + ":" + age);
}
调用:
show("LingXi", 22);
符合:
String → String
int → int
而:
show(22, "LingXi");
就不符合该方法的参数列表。
因此调用方法时必须考虑:
方法名
参数个数
参数类型
参数顺序
2.9 有返回值方法
如果方法计算得到一个结果,希望调用者继续使用,就可以返回数据。
例如:
public static int add(int a, int b) {
return a + b;
}
调用:
int result = add(10, 20);
整个过程:
10、20
↓
add()
↓
计算 10 + 20
↓
return 30
↓
调用表达式 add(10,20) 得到 30
↓
赋值给 result
因此:
add(10, 20)
本身是一个产生结果的表达式。
2.10 返回值类型
定义:
public static int add(int a, int b)
这里的:
int
表示:
方法返回结果的类型。
因此:
return a + b;
返回的数据必须能够满足该方法声明的返回类型要求。
例如:
public static boolean isAdult(int age) {
return age >= 18;
}
返回类型:
boolean
所以可以:
boolean result = isAdult(20);
2.11 return 的两个核心作用
return 有两个重要作用。
作用一:返回结果
例如:
public static int max(int a, int b) {
return a > b ? a : b;
}
这里:
return ...
把结果交给调用者。
作用二:立即结束当前方法
例如:
public static void divide(int a, int b) {
if (b == 0) {
System.out.println("除数不能为 0");
return;
}
System.out.println(a / b);
}
执行:
return;
后:
当前方法立即结束。
因此下面的:
System.out.println(a / b);
不会继续执行。
2.12 return 值; 与 return;
二者不要混淆。
有返回值:
return result;
既:
结束方法
+
返回一个结果
无返回值方法中:
return;
表示:
只结束当前方法
例如:
public static void checkAge(int age) {
if (age < 0) {
System.out.println("年龄不合法");
return;
}
System.out.println("年龄:" + age);
}
这种写法也常被称为:
提前返回(Early Return)。
合理使用提前返回可以减少过深的条件嵌套。
2.13 方法执行结束后会回到调用位置
例如:
public static void main(String[] args) {
System.out.println("A");
hello();
System.out.println("C");
}
public static void hello() {
System.out.println("B");
}
执行逻辑:
main
↓
A
↓
调用 hello
↓
B
↓
hello 结束
↓
返回 main 调用位置
↓
C
所以输出:
A
B
C
方法调用不是:
跳过去以后再也不回来。
而是:
暂时进入被调用方法,完成后返回调用者继续执行。
2.14 参数变量的生命周期
例如:
public static int add(int a, int b) {
int result = a + b;
return result;
}
每调用一次:
add(10, 20);
都会为本次调用创建对应的参数变量:
a
b
下一次:
add(100, 200);
又是另一组本次调用使用的参数变量。
因此不同方法调用之间不会共用同一个局部参数变量。
2.15 Java 参数传递:值传递
Java 方法参数采用:
值传递(Pass by Value)。
在当前基本数据类型阶段尤其容易理解。
例如:
public class PassValueDemo {
public static void main(String[] args) {
int number = 10;
change(number);
System.out.println(number);
}
public static void change(int value) {
value = 100;
}
}
调用:
change(number);
可以理解为:
number 当前保存 10
↓
把值 10 复制给参数 value
↓
value = 10
然后方法内部:
value = 100;
修改的是:
value
而不是调用者的:
number
所以 number 仍然保存:
10
可以用“复印件”理解:
number
│
│ 当前值 10
↓ 复制
value
修改复印件,不会直接修改原始变量。
引用类型参数仍然遵守值传递,只不过传递的值与对象引用有关,这部分将在数组和面向对象阶段继续学习。
2.16 什么是方法重载
方法重载(Overloading)表示:
同一个类中可以存在多个同名方法,只要它们的方法签名能够区分。
基础阶段重点看参数列表。
例如:
public static void print(int value) {
System.out.println(value);
}
public static void print(String value) {
System.out.println(value);
}
public static void print(int a, int b) {
System.out.println(a + "," + b);
}
三个方法都叫:
print
但是参数列表不同。
所以构成方法重载。
2.17 哪些差异能够构成重载
常见三种情况:
参数个数不同
public static void print(int a) {
}
public static void print(int a, int b) {
}
参数类型不同
public static void print(int value) {
}
public static void print(String value) {
}
参数类型顺序不同
public static void print(int a, double b) {
}
public static void print(double a, int b) {
}
都可以构成重载。
2.18 仅修改参数名不能构成重载
下面两个方法:
public static void add(int a, int b) {
}
public static void add(int x, int y) {
}
不能同时存在。
因为从方法调用者角度:
add(10, 20);
根本无法通过:
a/b
还是:
x/y
区分两个方法。
参数名称不是判断重载的关键。
2.19 仅修改返回值类型不能构成重载
下面也是错误的:
public static int getValue() {
return 1;
}
public static double getValue() {
return 1.0;
}
调用:
getValue();
编译器不能仅根据:
你希望拿到
int还是double
来把它们当作两个普通重载方法。
因此:
返回值类型本身不能作为方法重载的区分依据。
2.20 调用重载方法时会发生什么
例如:
public static void print(int value) {
System.out.println("int");
}
public static void print(String value) {
System.out.println("String");
}
调用:
print(10);
编译器根据:
方法名 print
实参个数 1
实参类型 int
找到合适的方法:
print(int value)
而:
print("Java");
则匹配:
print(String value)
因此方法重载的选择主要发生在:
编译期。
三、使用方法
3.1 两个整数求和
public class MethodDemo {
public static void main(String[] args) {
int result = add(10, 20);
System.out.println(result);
}
public static int add(int a, int b) {
return a + b;
}
}
3.2 判断奇偶数
public static boolean isEven(int number) {
return number % 2 == 0;
}
调用:
boolean result = isEven(10);
System.out.println(result);
3.3 获取最大值
public static int max(int a, int b) {
return a > b ? a : b;
}
3.4 打印指定次数
public static void printHello(int count) {
for (int i = 0; i < count; i++) {
System.out.println("Hello Java");
}
}
这里用到了循环;如果尚未学习循环,可以先把它作为后续会理解的案例。
3.5 提前结束方法
public static void divide(int a, int b) {
if (b == 0) {
System.out.println("除数不能为 0");
return;
}
System.out.println(a / b);
}
重点不是背代码,而是理解:
非法情况
↓
提前处理
↓
return
↓
正常主逻辑继续保持简单
3.6 方法重载
public class OverloadDemo {
public static void main(String[] args) {
print(100);
print("Java");
print(10, 20);
}
public static void print(int value) {
System.out.println(value);
}
public static void print(String value) {
System.out.println(value);
}
public static void print(int a, int b) {
System.out.println(a + "," + b);
}
}
对于使用者:
都叫 print
而编译器根据参数选择合适版本。
这就是重载给 API 带来的一个重要价值:
对“同类功能”使用统一的方法名称。
四、原理与进阶
4.1 方法签名与方法重载
在 Java 规范中,方法重载不是简单地判断:
方法名一样 + 随便哪里不一样
而是建立在:
方法签名(Method Signature)
之上。
基础阶段重点理解:
方法名
+
参数类型
以及相关参数列表信息。
返回值类型不属于普通重载选择的核心区分依据。
因此:
print(int)
print(String)
可以重载。
而:
int get()
double get()
不能只靠返回类型形成两个可区分的方法。
4.2 重载选择并不只是“类型完全相等”
例如:
public static void test(long value) {
System.out.println("long");
}
public static void main(String[] args) {
test(10);
}
虽然:
10
默认是 int,
但:
int → long
可以进行扩大转换。
所以这个方法仍然能够被调用。
随着未来学习:
包装类
自动装箱
可变参数
泛型
重载解析会更加复杂。
基础阶段不需要背完整算法,但必须知道:
编译器是在可适用的方法中按照 Java 的重载解析规则选择最合适的方法,而不只是做字符串式的参数匹配。
4.3 方法调用与调用栈的初步认识
例如:
main()
↓
calculate()
↓
max()
当一个方法调用另一个方法时,程序需要保存:
当前执行到了哪里
局部变量
参数
返回位置
然后进入下一个方法。
可以先建立一个抽象模型:
main
└── calculate
└── max
max 完成后:
max 返回
↓
calculate 继续
↓
calculate 返回
↓
main 继续
真正的 JVM 栈帧等内部机制属于后续更深入的 JVM 学习内容,本章不需要过度下钻。
4.4 方法应该承担单一、明确的职责
一个方法如果同时:
读取输入
计算 BMI
判断健康等级
发送网络请求
写数据库
打印结果
通常说明职责太多。
更合理的设计可能是:
readInput()
calculateBMI()
judgeLevel()
printResult()
这体现一个重要工程思想:
一个方法应该尽量完成一个明确的职责。
这种设计通常会提升:
可读性
复用性
可测试性
可维护性
五、实践应用
方法是所有 Java 项目最基本的代码组织单位之一。
例如学生管理:
addStudent()
deleteStudent()
findStudent()
updateStudent()
用户系统:
login()
register()
checkPassword()
订单系统:
calculatePrice()
createOrder()
cancelOrder()
算法程序:
binarySearch()
quickSort()
isPrime()
未来学习对象之后,这些方法还会进一步变成:
对象的行为
Service 业务逻辑
Controller 请求处理
Mapper 数据访问
所以真正需要形成的能力不是:
会背方法定义格式。
而是:
看见一个功能,能够判断是否应该把它抽成一个独立方法。
六、常见问题
6.1 方法定义在 main 里面吗?
普通 Java 方法不能像这样定义:
public static void main(String[] args) {
public static void test() {
}
}
方法通常作为类的成员定义。
例如:
public class Demo {
public static void main(String[] args) {
}
public static void test() {
}
}
6.2 方法一定需要参数吗?
不一定。
public static void hello() {
}
就是无参数方法。
参数是否存在取决于:
这个功能是否需要调用者提供外部数据。
6.3 方法一定要返回数据吗?
不一定。
例如:
public static void printHello() {
System.out.println("Hello");
}
返回类型使用:
void
即可。
6.4 void 方法能使用 return 吗?
可以使用:
return;
提前结束方法。
但不能像有返回值方法那样:
return 100;
向调用者返回一个普通结果值。
6.5 return 后还能继续写正常执行的语句吗?
如果一条语句确定永远位于无条件 return 之后,就会成为不可达代码。
例如:
return;
// 永远不可能执行
System.out.println("Hello");
这种代码不能作为正常逻辑存在。
6.6 形参和实参是不是同一个变量?
不是。
例如:
int number = 10;
change(number);
方法:
public static void change(int value) {
}
number 和 value 是两个不同变量。
调用时,参数变量会接收实参表达式计算得到的值。
6.7 Java 是引用传递还是值传递?
Java 方法调用采用值传递。
基本类型容易理解:
复制基本数据值
引用类型同样是值传递,只不过复制的是引用相关的值。
不要形成:
基本类型是值传递
对象是引用传递
这种错误二分法。
引用类型的具体行为将在对象和数组章节继续理解。
6.8 仅修改返回值类型能构成重载吗?
不能。
例如:
int get()
double get()
不能仅凭返回值类型区分为合法的普通重载。
6.9 参数名称不同算重载吗?
不算。
test(int a)
test(int b)
方法参数名称不同,但调用方式无法区分。
6.10 方法是不是越多越好?
不是。
不应该把:
每一两行代码
机械拆成一个方法。
是否拆分主要看:
职责是否独立
是否会重复使用
是否降低复杂度
是否提高可读性
是否便于测试
七、练习与验收
7.1 知识问答
- 什么是方法?为什么方法可以理解成一个独立功能单元?
- 方法定义通常包含哪些部分?
- 方法为什么必须调用后才会执行?
- 什么是形参?什么是实参?
- 参数个数、类型和顺序为什么重要?
- 什么叫返回值?
void表示什么?return 数据;与return;有什么区别?- Java 参数传递采用什么机制?
- 为什么修改基本类型形参不会直接修改调用者的变量?
- 什么是方法重载?
- 哪三类参数列表差异经常可以构成重载?
- 仅修改形参名称能否形成重载?
- 仅修改返回值类型能否形成重载?
- 为什么合理拆分方法能够提升代码质量?
7.2 代码阅读
禁止运行:
public class MethodRead01 {
public static void main(String[] args) {
int x = max(10, 20);
System.out.println(x);
print(x);
}
public static int max(int a, int b) {
return a > b ? a : b;
}
public static void print(int value) {
if (value < 0) {
return;
}
System.out.println(value);
}
}
要求:
- 按执行顺序描述
main → max → main → print → main。 max(10, 20)的结果是什么?- 如果删除
max中的return会发生什么? print()中的return;有什么作用?
继续分析:
public class PassValueRead {
public static void main(String[] args) {
int number = 10;
change(number);
System.out.println(number);
}
public static void change(int value) {
value = 100;
}
}
要求:
- 不运行程序预测输出。
- 画出
number → value的参数传递过程。 - 解释为什么修改
value不等于修改number。
7.3 手写代码
- 手写
add(int a, int b)。 - 手写
max(int a, int b)。 - 手写
isEven(int number)。 - 手写一个无参数无返回值
printHello()。 - 手写一个
divide(int a, int b),当b == 0时提前结束。 - 设计三个同名
print方法,分别接收int、String、两个int。 - 把一个包含输入、计算和输出的长
main拆分成至少三个职责明确的方法。
7.4 Debug
下面方法无法正常通过编译:
public static int add(int a, int b) {
System.out.println(a + b);
}
要求:
- 找出问题。
- 区分“打印结果”和“返回结果”。
- 根据不同需求设计两种合理修改方案。
继续:
public static int test(int a) {
return a;
}
public static double test(int b) {
return b;
}
要求:
- 判断是否构成合法重载。
- 说明理由。
- 在保留方法名
test的前提下设计合法重载。
7.5 综合训练
重构一个控制台“成绩分析程序”。
要求将程序拆成:
readScore()
isValidScore()
getLevel()
printResult()
或者你认为更合理的方法。
要求:
- 每个方法职责明确。
- 合理设计参数和返回值。
- 至少存在一个有返回值方法。
- 至少存在一个
void方法。 - 至少使用一次提前
return。 - 完成后说明为什么这样拆分,而不是把所有代码放进
main。
7.6 本章验收
关闭资料后确认:
- [ ] 能从零写出一个完整方法。
- [ ] 能正确设计方法名、参数和返回类型。
- [ ] 能区分形参与实参。
- [ ] 能说明调用方法后的控制流。
- [ ] 能使用
return返回数据。 - [ ] 能使用
return;提前结束方法。 - [ ] 能解释 Java 的值传递。
- [ ] 能判断两个方法是否构成重载。
- [ ] 知道返回值类型不能单独构成重载。
- [ ] 能将一个过长的
main主动拆成多个小方法。
如果只能背:
public static 返回值 方法名(...)
却不能根据具体需求决定:
要不要参数
要不要返回值
方法应该负责什么
那么还没有真正掌握方法。