Appearance
方法
方法是完成特定功能的代码块,是 Java 程序的基本组成单元。方法可以提高代码的复用性和可维护性。
方法的定义
基本语法
text
修饰符 返回值类型 方法名(参数列表) {
方法体
return 返回值;
}方法定义示例
java
public class MethodDefinition {
public static void main(String[] args) {
// 调用方法
int result = add(10, 20);
System.out.println("10 + 20 = " + result);
printHello();
greet("张三");
}
/**
* 定义一个加法方法
* @param a 第一个加数
* @param b 第二个加数
* @return 两数之和
*/
public static int add(int a, int b) {
int sum = a + b;
return sum; // 返回计算结果
}
/**
* 无参数无返回值的方法
*/
public static void printHello() {
System.out.println("Hello, Java!");
}
/**
* 有参数无返回值的方法
* @param name 姓名
*/
public static void greet(String name) {
System.out.println("你好," + name + "!");
}
}方法组成部分
java
public class MethodComponents {
// public static:修饰符
// int:返回值类型
// calculate:方法名
// int a, int b:参数列表
public static int calculate(int a, int b) {
// 方法体
int result = a * b + 100;
// return:返回语句
return result;
}
// 无返回值的方法使用 void
public static void showMessage(String message) {
System.out.println("消息:" + message);
// void 方法可以没有 return,或者只写 return;
return; // 可选
}
}方法的调用
调用方式
java
public class MethodCall {
public static void main(String[] args) {
// 直接调用
printInfo();
// 赋值调用(有返回值的方法)
int max = getMax(10, 20);
System.out.println("最大值: " + max);
// 输出调用
System.out.println("最小值: " + getMin(10, 20));
// 表达式中调用
int result = getMax(5, 8) * 2 + getMin(3, 7);
System.out.println("计算结果: " + result);
// 嵌套调用
int nested = getMax(getMax(1, 2), getMax(3, 4));
System.out.println("嵌套调用结果: " + nested);
}
public static void printInfo() {
System.out.println("这是一个无返回值的方法");
}
public static int getMax(int a, int b) {
return a > b ? a : b;
}
public static int getMin(int a, int b) {
return a < b ? a : b;
}
}调用其他类的方法
java
// 定义一个工具类
class MathUtils {
// 静态方法:通过类名调用
public static int square(int n) {
return n * n;
}
// 实例方法:需要创建对象调用
public int cube(int n) {
return n * n * n;
}
}
public class CallOtherClass {
public static void main(String[] args) {
// 调用静态方法:类名.方法名
int sq = MathUtils.square(5);
System.out.println("5的平方: " + sq);
// 调用实例方法:对象.方法名
MathUtils utils = new MathUtils();
int cb = utils.cube(3);
System.out.println("3的立方: " + cb);
}
}参数传递
基本类型参数
基本类型参数是值传递,方法内修改不影响原值。
java
public class PrimitiveParam {
public static void main(String[] args) {
int num = 10;
System.out.println("调用前: num = " + num); // 10
changeValue(num);
System.out.println("调用后: num = " + num); // 10(值不变)
}
public static void changeValue(int n) {
n = 100; // 修改的是副本,不影响原值
System.out.println("方法内: n = " + n); // 100
}
}引用类型参数
引用类型参数传递的是地址,方法内修改会影响原对象。
java
public class ReferenceParam {
public static void main(String[] args) {
// 数组是引用类型
int[] arr = {1, 2, 3};
System.out.println("调用前: " + java.util.Arrays.toString(arr)); // [1, 2, 3]
modifyArray(arr);
System.out.println("调用后: " + java.util.Arrays.toString(arr)); // [100, 2, 3]
// 对象也是引用类型
Person person = new Person();
person.name = "张三";
System.out.println("调用前: " + person.name); // 张三
modifyPerson(person);
System.out.println("调用后: " + person.name); // 李四
}
public static void modifyArray(int[] array) {
array[0] = 100; // 修改数组元素,影响原数组
}
public static void modifyPerson(Person p) {
p.name = "李四"; // 修改对象属性,影响原对象
}
}
class Person {
String name;
}可变参数
Java 支持可变参数,允许传递任意数量的同类型参数。
java
public class VarargsDemo {
public static void main(String[] args) {
// 传递多个参数
int sum1 = sum(1, 2, 3);
System.out.println("sum(1, 2, 3) = " + sum1); // 6
// 传递数组
int[] arr = {1, 2, 3, 4, 5};
int sum2 = sum(arr);
System.out.println("sum(arr) = " + sum2); // 15
// 不传参数
int sum3 = sum();
System.out.println("sum() = " + sum3); // 0
// 可变参数与普通参数混用
printInfo("学生", 90, 85, 95);
}
/**
* 可变参数方法
* @param numbers 可变参数,本质是数组
* @return 所有参数的和
*/
public static int sum(int... numbers) {
int total = 0;
for (int num : numbers) {
total += num;
}
return total;
}
/**
* 可变参数必须放在参数列表最后
* @param name 姓名
* @param scores 成绩(可变参数)
*/
public static void printInfo(String name, int... scores) {
System.out.print(name + " 的成绩:");
for (int score : scores) {
System.out.print(score + " ");
}
System.out.println();
}
}方法重载
方法重载是指在同一个类中定义多个同名但参数列表不同的方法。
重载规则
text
┌─────────────────────────────────────────────────────────────────┐
│ 方法重载规则 │
├─────────────────────────────────────────────────────────────────┤
│ 1. 方法名必须相同 │
│ 2. 参数列表必须不同(参数个数、类型、顺序) │
│ 3. 返回值类型可以相同也可以不同 │
│ 4. 与访问修饰符无关 │
└─────────────────────────────────────────────────────────────────┘重载示例
java
public class MethodOverload {
public static void main(String[] args) {
// 根据参数类型自动匹配方法
System.out.println("add(10, 20) = " + add(10, 20)); // int
System.out.println("add(10.5, 20.5) = " + add(10.5, 20.5)); // double
System.out.println("add(10, 20, 30) = " + add(10, 20, 30)); // 三个参数
}
// 两个 int 参数
public static int add(int a, int b) {
System.out.println("调用 int add(int, int)");
return a + b;
}
// 两个 double 参数(参数类型不同)
public static double add(double a, double b) {
System.out.println("调用 double add(double, double)");
return a + b;
}
// 三个 int 参数(参数个数不同)
public static int add(int a, int b, int c) {
System.out.println("调用 int add(int, int, int)");
return a + b + c;
}
// 参数顺序不同
public static void show(int a, String b) {
System.out.println("int, String: " + a + ", " + b);
}
public static void show(String a, int b) {
System.out.println("String, int: " + a + ", " + b);
}
}重载与可变参数
java
public class OverloadVarargs {
public static void main(String[] args) {
print(1);
print(1, 2);
print(1, 2, 3);
}
// 优先匹配固定参数的方法
public static void print(int a) {
System.out.println("一个参数: " + a);
}
public static void print(int a, int b) {
System.out.println("两个参数: " + a + ", " + b);
}
// 可变参数作为后备选项
public static void print(int... nums) {
System.out.print("多个参数: ");
for (int num : nums) {
System.out.print(num + " ");
}
System.out.println();
}
}方法递归
递归是方法调用自身的过程,适合解决可以分解为相似子问题的问题。
递归基本结构
java
public class RecursionBasic {
public static void main(String[] args) {
// 计算 5 的阶乘
int result = factorial(5);
System.out.println("5! = " + result); // 120
// 计算 1 到 100 的和
int sum = sumToN(100);
System.out.println("1到100的和 = " + sum); // 5050
}
/**
* 计算阶乘(递归)
* n! = n * (n-1)!
*/
public static int factorial(int n) {
// 递归终止条件(必须有)
if (n <= 1) {
return 1;
}
// 递归调用
return n * factorial(n - 1);
}
/**
* 计算 1 到 n 的和(递归)
*/
public static int sumToN(int n) {
if (n <= 0) {
return 0;
}
return n + sumToN(n - 1);
}
}经典递归案例
java
public class RecursionExamples {
public static void main(String[] args) {
// 斐波那契数列
System.out.println("斐波那契数列前10项:");
for (int i = 1; i <= 10; i++) {
System.out.print(fibonacci(i) + " ");
}
System.out.println();
// 汉诺塔
System.out.println("\n汉诺塔(3个盘子):");
hanoi(3, 'A', 'B', 'C');
// 二分查找(递归)
int[] arr = {1, 3, 5, 7, 9, 11, 13};
int index = binarySearch(arr, 7, 0, arr.length - 1);
System.out.println("\n7 的索引: " + index);
}
/**
* 斐波那契数列
* 1, 1, 2, 3, 5, 8, 13, 21, ...
*/
public static int fibonacci(int n) {
if (n <= 2) {
return 1;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
/**
* 汉诺塔问题
* @param n 盘子数量
* @param from 起始柱
* @param aux 辅助柱
* @param to 目标柱
*/
public static void hanoi(int n, char from, char aux, char to) {
if (n == 1) {
System.out.println("移动盘子 1 从 " + from + " 到 " + to);
return;
}
// 将 n-1 个盘子从 from 移到 aux
hanoi(n - 1, from, to, aux);
// 将第 n 个盘子从 from 移到 to
System.out.println("移动盘子 " + n + " 从 " + from + " 到 " + to);
// 将 n-1 个盘子从 aux 移到 to
hanoi(n - 1, aux, from, to);
}
/**
* 二分查找(递归版)
*/
public static int binarySearch(int[] arr, int target, int left, int right) {
if (left > right) {
return -1; // 未找到
}
int mid = (left + right) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
return binarySearch(arr, target, mid + 1, right);
} else {
return binarySearch(arr, target, left, mid - 1);
}
}
}递归与循环对比
java
public class RecursionVsLoop {
public static void main(String[] args) {
int n = 10;
// 递归方式
long start1 = System.nanoTime();
long result1 = factorialRecursive(n);
long end1 = System.nanoTime();
System.out.println("递归结果: " + result1 + ", 耗时: " + (end1 - start1) + " ns");
// 循环方式
long start2 = System.nanoTime();
long result2 = factorialLoop(n);
long end2 = System.nanoTime();
System.out.println("循环结果: " + result2 + ", 耗时: " + (end2 - start2) + " ns");
}
// 递归方式
public static long factorialRecursive(int n) {
if (n <= 1) return 1;
return n * factorialRecursive(n - 1);
}
// 循环方式
public static long factorialLoop(int n) {
long result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
}方法的作用域
局部变量
java
public class MethodScope {
// 类变量(成员变量)
private int instanceVar = 10;
private static int staticVar = 20;
public void method1() {
// 局部变量:方法内有效
int localVar = 30;
System.out.println("局部变量: " + localVar);
System.out.println("实例变量: " + instanceVar);
System.out.println("静态变量: " + staticVar);
}
public void method2() {
// localVar 在这里不可访问
// System.out.println(localVar); // 编译错误
// 可以定义同名局部变量
int instanceVar = 100; // 遮蔽了实例变量
System.out.println("局部 instanceVar: " + instanceVar); // 100
System.out.println("实例变量: " + this.instanceVar); // 10
}
public void method3(int param) {
// 参数也是局部变量
System.out.println("参数: " + param);
// 代码块内的局部变量
{
int blockVar = 50;
System.out.println("块变量: " + blockVar);
}
// blockVar 在这里不可访问
// System.out.println(blockVar); // 编译错误
}
}方法最佳实践
单一职责原则
java
public class MethodBestPractice {
public static void main(String[] args) {
// 好的做法:每个方法只做一件事
int[] numbers = {5, 2, 8, 1, 9};
printArray(numbers);
sortArray(numbers);
printArray(numbers);
int max = findMax(numbers);
System.out.println("最大值: " + max);
}
// 好的做法:方法名清晰表达功能
public static void printArray(int[] arr) {
System.out.println(java.util.Arrays.toString(arr));
}
public static void sortArray(int[] arr) {
java.util.Arrays.sort(arr);
}
public static int findMax(int[] arr) {
int max = arr[0];
for (int num : arr) {
if (num > max) {
max = num;
}
}
return max;
}
// 不好的做法:一个方法做太多事
// public static void printSortAndFindMax(int[] arr) { ... }
}参数和返回值设计
java
public class ParameterDesign {
public static void main(String[] args) {
// 参数不宜过多(建议不超过 3-4 个)
// 如果参数太多,考虑使用对象封装
// 好的做法
User user = new User("张三", 25, "zhangsan@example.com");
registerUser(user);
// 不好的做法
// registerUser("张三", 25, "zhangsan@example.com", "13800138000", "北京市", ...);
}
public static void registerUser(User user) {
System.out.println("注册用户: " + user.name);
}
// 返回值要有意义
// 好的做法:返回操作结果
public static boolean deleteUser(int userId) {
// 删除逻辑
return true; // 返回是否成功
}
// 好的做法:返回 null 或 Optional 表示无结果
public static User findUserById(int userId) {
// 查找逻辑
return null; // 未找到返回 null
}
}
class User {
String name;
int age;
String email;
public User(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
}小结
本章我们学习了:
- 方法定义:修饰符、返回值、方法名、参数列表
- 方法调用:直接调用、赋值调用、输出调用
- 参数传递:值传递、引用传递、可变参数
- 方法重载:同名不同参
- 方法递归:方法调用自身
- 最佳实践:单一职责、合理设计参数和返回值
下一章,我们将学习 数组,了解 Java 中数组的使用。
