方法的定义
方法是一段封装特定功能的、可重复调用的代码块。
语法格式:
修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ...) { 方法体 return 返回值; }各组成部分说明:
组成部分 | 说明 |
修饰符 | 控制访问权限和调用方式,如 |
返回值类型 | 方法返回结果的数据类型;无返回值用 |
方法名 | 小驼峰命名,见名知意 |
参数列表 | 形式参数(形参),多个用逗号分隔;无参数则留空 |
方法体 | 实现功能的具体代码 |
| 结束方法执行并返回结果; |
示例:
public static int getMax(int num1, int num2) { if (num1 > num2) { return num1; } else { return num2; } } int max = getMax(10, 20); // max = 20方法定义后不会自动执行,必须通过方法名(实参)显式调用。
方法的分类
按是否有参数和是否有返回值,方法分为四类:
分类 | 声明示例 | 调用方式 |
无参无返回值 |
|
|
无参有返回值 |
|
|
有参无返回值 |
|
|
有参有返回值 |
|
|
形参和实参
- 形参:方法定义时括号中的变量,是占位符
- 实参:调用方法时传入的具体值
要求:实参的类型、数量、顺序必须与形参一致,否则编译报错。
public static int add(int num1, int num2) { // num1、num2 是形参 return num1 + num2; } add(10, 20); // 10、20 是实参 add(a, 3); // 实参可以是变量 add(2 + 3, a * 2); // 实参可以是表达式方法重载
规则
同一个类中,方法名相同、参数列表不同,构成方法重载。
判断条件 | 说明 |
方法名 | 必须相同 |
参数个数 | 不同即构成重载 |
参数类型 | 不同即构成重载 |
参数顺序 | 不同即构成重载(如 |
与返回值类型无关,与参数名无关。
以下写法不构成重载,会编译报错:
// 编译错误:仅返回值类型不同 public static int add(int a, int b) { return a + b; } public static double add(int a, int b) { return a + b; } // 编译错误:仅参数名不同 public static int add(int a, int b) { return a + b; } public static int add(int x, int y) { return x + y; }原因:add(1, 2)调用时编译器无法根据返回值判断目标方法。
重载匹配顺序
编译器按以下优先级匹配重载方法:
- 精确类型匹配
- 自动类型提升(
byte→short→int→long→float→double) - 自动装箱/拆箱
- 可变参数(优先级最低)
public static void test(long a) { System.out.println("long"); } public static void test(double a) { System.out.println("double"); } test(10); // 输出 "long":int → long 比 int → double 更近重载示例
public class OverloadDemo { public static int add(int a, int b) { return a + b; } public static double add(double a, double b) { // 参数类型不同 return a + b; } public static int add(int a, int b, int c) { // 参数个数不同 return a + b + c; } public static double add(int a, double b) { // 参数顺序不同 return a + b; } }值传递
Java 只有一种参数传递方式:值传递。实参将自身的值复制一份传给形参,方法内对形参的修改不影响实参。
"值"的含义取决于实参类型:
实参类型 | 传递的值 | 方法内修改的影响 |
基本类型 | 数据值本身 | 不影响实参 |
引用类型 | 堆内存地址的副本 | 修改地址本身不影响实参;修改地址指向的对象内容会影响原对象 |
基本类型
public static void change(int x) { x = 100; // 修改的是副本 } int a = 10; change(a); System.out.println(a); // 10,不受影响引用类型:修改对象内容
public static void changeContent(int[] arr) { arr[0] = 100; // arr 与实参指向同一对象 } int[] a = {1, 2}; changeContent(a); System.out.println(a[0]); // 100,原数组内容被修改引用类型:修改引用本身
public static void changeRef(int[] arr) { arr = new int[]{3, 4}; // arr 指向新对象,不影响实参 } int[] a = {1, 2}; changeRef(a); System.out.println(a[0]); // 1,原数组未受影响方法调用内存模型
JVM 内存分区
内存区域 | 作用 |
栈(Stack) | 每个线程独享,存储方法调用栈帧(局部变量、形参、返回地址)。方法调用入栈,执行完毕出栈 |
堆(Heap) | 所有线程共享,存储对象实例和数组。栈中的引用变量存储的是堆地址 |
方法调用流程
public static int add(int x, int y) { int result = x + y; return result; } public static void main(String[] args) { int a = 10; int b = 20; int sum = add(a, b); }执行步骤:
main入栈:栈帧中存储a=10、b=20- 调用
add(a, b):a=10、b=20的值复制给形参x、y;add栈帧入栈,计算result=30 add出栈:return 30将结果传给main的sum;add栈帧弹出main出栈:程序结束
递归
方法调用自身的写法,须满足两个条件:
- 有递归出口(终止条件)
- 每次递归调用,问题规模缩小
public static int factorial(int n) { if (n == 1) return 1; // 递归出口 return n * factorial(n - 1); // 问题规模缩小 }递归层级过深会导致栈帧无限堆积,抛出StackOverflowError。
基本类型与引用类型
对比维度 | 基本类型(8种) | 引用类型 |
存储内容 | 数据值本身 | 堆中对象的地址 |
内存位置 | 栈(方法栈帧) | 引用在栈,对象在堆 |
默认值 | 对应类型的零值( |
|
赋值/传参 | 复制值,互不影响 | 复制地址,修改内容相互影响 |
是否可为 | 否 | 是 |
Java 的 8 种基本类型:
分类 | 类型 | 占用 | 取值范围 |
整数 |
| 1B | -128 ~ 127 |
| 2B | -32768 ~ 32767 | |
| 4B | -2³¹ ~ 2³¹-1 | |
| 8B | -2⁶³ ~ 2⁶³-1 | |
浮点 |
| 4B | 精度 6~7 位 |
| 8B | 精度 15~16 位 | |
字符 |
| 2B | 0 ~ 65535 |
布尔 |
| JVM 实现相关 |
|
注意事项
- 方法不能嵌套定义:Java 不允许在一个方法体内定义另一个方法
return执行后方法立即结束,其后代码不会执行(编译可通过但不可达)- 声明了非
void返回值类型的方法,所有执行路径都必须有return语句 - 调用方法时,实参的类型、数量、顺序必须与形参一致
- 引用类型变量值为
null时调用方法或访问属性会抛出NullPointerException