Java 方法
Java - 方法
Section titled “Java - 方法”在 Java 中,**方法(method)**是一个执行特定任务的代码块。方法允许你将相关的语句分组,给它们一个名称,并在需要时通过调用该名称来执行。这有助于代码组织、重用,并使程序更易于理解和维护。
可以把方法想象成食谱:它们有一个名称(例如,“bakeCake”),可能需要配料(参数),执行一系列步骤(方法体),并且可能产生一个结果(返回值,就像烤好的蛋糕)。
你已经使用过 System.out.println() 等方法。现在,让我们学习如何创建自己的方法。
方法定义的基本结构(语法)是:
modifier(s) returnType methodName(parameterList) throws ExceptionType(s) { // 方法体:执行任务的语句 // ... return value; // 如果 returnType 不是 void,则必需}modifier(s): (可选)关键字,如public、private、protected、static、final、abstract。它们控制访问和行为。我们稍后会详细介绍这些。public:可从任何其他类访问。static:属于类本身,而不是特定的对象实例。可以使用ClassName.methodName()调用。returnType: 方法返回值的 数据类型。如果方法不返回任何值,使用关键字void。methodName: 你给方法起的名称。遵循命名约定(camelCase,以小写字母开头,例如,calculateSum,printUserDetails)。parameterList: (可选)方法接受的输入变量的逗号分隔列表。每个参数都有一个类型和一个名称(例如,int number1, String message)。如果没有参数,则括号()留空。throws ExceptionType(s): (可选)指定方法可能抛出的已检查异常的类型。将在异常章节中介绍。- 方法体: 包含实现方法逻辑的语句的代码块(在
{}中)。 return value;: 如果returnType不是void,方法必须使用return关键字后跟指定returnType的值,将结果返回给调用者。
方法定义示例:
Section titled “方法定义示例:”/** * 计算两个整数的和。 * @param num1 第一个整数。 * @param num2 第二个整数。 * @return num1 和 num2 的和。 */public static int addNumbers(int num1, int num2) { int sum = num1 + num2; return sum; // 返回一个整数值}
/** * 向控制台打印问候消息。 * 此方法不返回任何值。 * @param name 要问候的名称。 */public static void printGreeting(String name) { System.out.println("Hello, " + name + "!"); // void 方法不需要 return 语句(或者使用 'return;' 提前退出)}要执行方法,你需要调用它,使用它的名称,后面跟着括号 ()。如果方法需要参数(实参),你在括号内提供值,需要匹配参数列表的类型和顺序。
- 程序控制转移到被调用方法的开头。
- 方法体执行。
- 在以下情况下,控制返回到方法调用之后的点:
- 执行了
return语句(如果适用,返回一个值)。 - 到达方法体 (
}) 的末尾(对于void方法)。
方法调用示例:
Section titled “方法调用示例:”public class MethodDemo {
public static void main(String[] args) { // 调用 void 方法 printGreeting("Alice"); // 将 "Alice" 作为 'name' 参数的实参传递
// 调用返回值的方法 int numberA = 10; int numberB = 25; int result = addNumbers(numberA, numberB); // 调用并存储返回值
System.out.println("The sum is: " + result);
// 你也可以直接使用返回值 System.out.println("Sum of 5 and 7: " + addNumbers(5, 7)); }
// --- 来自前面示例的方法定义 --- public static int addNumbers(int num1, int num2) { int sum = num1 + num2; return sum; }
public static void printGreeting(String name) { System.out.println("Hello, " + name + "!"); }}输出:
Hello, Alice!The sum is: 35Sum of 5 and 7: 12按值传递 vs. 按引用传递(澄清)
Section titled “按值传递 vs. 按引用传递(澄清)”Java 严格按值传递。 这意味着当你将变量传递给方法时:
- 对于基本类型(int, float, boolean 等): 变量值的副本被传递给方法参数。在方法内部对参数所做的更改不会影响方法外部的原始变量。
- 对于引用类型(对象,数组): 变量的引用(内存地址)的副本被传递。原始变量和方法参数现在都指向内存中的同一个对象。因此,如果方法修改了对象本身(例如,改变对象的字段,向数组列表中添加元素),这些更改将反映在方法外部,因为它们作用于同一个对象。然而,如果方法尝试将参数重新赋值给一个新对象(
parameter = new Object();),这只会改变参数的引用副本,而不会影响方法外部的原始变量。
示例(基本类型按值传递):
Section titled “示例(基本类型按值传递):”public class PassByValuePrimitive { public static void main(String[] args) { int originalValue = 10; System.out.println("Before calling method: " + originalValue); tryToModify(originalValue); System.out.println("After calling method: " + originalValue); // 仍然是 10 }
public static void tryToModify(int number) { number = number + 5; // 修改副本 System.out.println("Inside method: " + number); }}输出:
Before calling method: 10Inside method: 15After calling method: 10示例(引用类型按值传递 - 修改对象状态):
Section titled “示例(引用类型按值传递 - 修改对象状态):”import java.util.Arrays;
public class PassByValueReference { public static void main(String[] args) { int[] originalArray = {1, 2, 3}; System.out.println("Before calling method: " + Arrays.toString(originalArray)); modifyArray(originalArray); System.out.println("After calling method: " + Arrays.toString(originalArray)); // 数组被修改了 }
// 参数 'arr' 接收到原始数组引用的副本 public static void modifyArray(int[] arr) { if (arr != null && arr.length > 0) { arr[0] = 99; // 修改引用指向的对象 System.out.println("Inside method: " + Arrays.toString(arr)); } // arr = new int[]{4, 5, 6}; // 这只会改变局部变量 'arr' 的引用,不会改变 originalArray }}输出:
Before calling method: [1, 2, 3]Inside method: [99, 2, 3]After calling method: [99, 2, 3]方法重载 (Method Overloading)
Section titled “方法重载 (Method Overloading)”方法重载允许你在同一个类中定义多个同名的方法,只要它们的参数列表不同。不同之处可以体现在:
- 参数的数量。
- 参数的数据类型。
- 参数的数据类型的顺序。
仅凭返回值类型不足以重载方法。
重载允许你根据输入实参提供执行类似操作的不同方式。编译器根据方法调用中提供的实参确定调用哪个重载方法。
示例(重载):
Section titled “示例(重载):”public class OverloadDemo {
public static void main(String[] args) { System.out.println("Sum of 2 ints: " + add(5, 10)); System.out.println("Sum of 3 ints: " + add(5, 10, 15)); System.out.println("Sum of 2 doubles: " + add(3.5, 2.7)); printInfo("Alice"); printInfo("Bob", 30); }
// 重载的 add 方法 public static int add(int a, int b) { System.out.println("-> Called add(int, int)"); return a + b; }
public static int add(int a, int b, int c) { System.out.println("-> Called add(int, int, int)"); return a + b + c; }
public static double add(double a, double b) { System.out.println("-> Called add(double, double)"); return a + b; }
// 重载的 printInfo 方法 public static void printInfo(String name) { System.out.println("-> Called printInfo(String)"); System.out.println("Name: " + name); }
public static void printInfo(String name, int age) { System.out.println("-> Called printInfo(String, int)"); System.out.println("Name: " + name + ", Age: " + age); }}输出:
-> Called add(int, int)Sum of 2 ints: 15-> Called add(int, int, int)Sum of 3 ints: 30-> Called add(double, double)Sum of 2 doubles: 6.2-> Called printInfo(String)Name: Alice-> Called printInfo(String, int)Name: Bob, Age: 30构造方法 (Constructors)
Section titled “构造方法 (Constructors)”**构造方法(constructor)**是一种特殊类型的方法,用于在使用 new 关键字创建对象时初始化对象。它看起来类似于普通方法,但有特定的规则:
- 它必须与类同名。
- 它没有显式返回值类型,甚至没有
void。 - 当类的对象被实例化(
new ClassName(...))时,它会自动被调用。
构造方法主要用于为对象的实例变量(字段)设置初始值。
如果你在类中没有定义任何构造方法,Java 会自动提供一个默认构造方法。这个默认构造方法不接受任何参数,并将实例变量初始化为它们的默认值(数字为 0,布尔值为 false,对象为 null)。
然而,如果你确实定义了任何构造方法(无论带参数还是不带参数),默认构造方法将不会自动提供。
与普通方法一样,构造方法也可以重载。
示例(构造方法):
Section titled “示例(构造方法):”class Dog { String name; int age;
// 构造方法 1:无参数(用默认名称初始化) public Dog() { this.name = "Unknown"; // 'this' 指代当前对象 this.age = 0; System.out.println("Dog() constructor called."); }
// 构造方法 2:接受 name 作为参数 public Dog(String name) { this.name = name; this.age = 0; System.out.println("Dog(String) constructor called."); }
// 构造方法 3:接受 name 和 age public Dog(String name, int age) { this.name = name; this.age = age; System.out.println("Dog(String, int) constructor called."); }
public void displayInfo() { System.out.println("Dog [Name=" + name + ", Age=" + age + "]"); }}
public class ConstructorDemo { public static void main(String[] args) { Dog dog1 = new Dog(); // 调用 Dog() Dog dog2 = new Dog("Buddy"); // 调用 Dog(String) Dog dog3 = new Dog("Lucy", 3); // 调用 Dog(String, int)
dog1.displayInfo(); dog2.displayInfo(); dog3.displayInfo(); }}输出:
Dog() constructor called.Dog(String) constructor called.Dog(String, int) constructor called.Dog [Name=Unknown, Age=0]Dog [Name=Buddy, Age=0]Dog [Name=Lucy, Age=3]可变参数 (Varargs)
Section titled “可变参数 (Varargs)”Varargs 在 Java 5 中引入,允许方法接受可变数量的同类型实参。
语法:在方法签名中,指定类型后跟省略号 (...)。
`public static void myMethod(String fixedArg, int... numbers)`- Varargs 参数(示例中的
int... numbers)在方法内部被视为该类型的数组(int[])。 - 一个方法只能有一个 varargs 参数。
- varargs 参数必须是方法签名中的最后一个参数。
- 你可以为 varargs 参数传递零个或多个实参来调用方法,或者传递指定类型的数组。
示例(Varargs):
Section titled “示例(Varargs):”public class VarargsDemo {
public static void main(String[] args) { printNumbers("Set 1:", 1, 2, 3); printNumbers("Set 2:", 10, 20, 30, 40, 50); printNumbers("Set 3:"); // 用零个 varargs 调用
int[] data = {100, 200}; printNumbers("Set 4:", data); // 用一个数组调用 }
// 方法接受一个标题和可变数量的整数 public static void printNumbers(String title, int... numbers) { System.out.print(title + " "); if (numbers.length == 0) { System.out.println(" (No numbers)"); return; }
for (int i = 0; i < numbers.length; i++) { System.out.print(numbers[i]); if (i < numbers.length - 1) { System.out.print(", "); } } System.out.println(); }}输出:
Set 1: 1, 2, 3Set 2: 10, 20, 30, 40, 50Set 3: (No numbers)Set 4: 100, 200命令行参数 (Command-Line Arguments)
Section titled “命令行参数 (Command-Line Arguments)”main 方法作为 Java 应用程序的入口点,有一个参数 String[] args(或 String... args)。当程序在命令行执行时,传递给程序的任何参数都会被这个数组接收。
public class CommandLineArgs { public static void main(String[] args) { System.out.println("Number of arguments received: " + args.length);
if (args.length > 0) { System.out.println("Arguments are:"); for (int i = 0; i < args.length; i++) { System.out.println("args[" + i + "]: " + args[i]); } } }}编译并运行:
javac CommandLineArgs.javajava CommandLineArgs firstArg "Second Argument" 123输出:
Number of arguments received: 3Arguments are:args[0]: firstArgargs[1]: Second Argumentargs[2]: 123注意:实参是以字符串的形式传递的。如果你需要数字,你需要解析它们(例如,使用 Integer.parseInt())。
finalize() 方法(已废弃 - 避免使用)
Section titled “finalize() 方法(已废弃 - 避免使用)”较旧的 Java 版本有一个 finalize() 方法(定义在 Object 类中)。其意图是重写它,以便在对象被垃圾回收之前执行清理操作。然而,finalize() 有明显的缺点:
- 不可预测的时机: 无法保证
finalize()何时 或甚至 是否会被调用。 - 性能问题: 终结化可能会延迟垃圾回收并影响性能。
- 容易出错: 在
finalize()中抛出的异常会被忽略。 - 安全风险: 可能导致对象“复活”。
从 Java 9 起,finalize() 已被废弃,应避免使用。 现代资源清理的替代方案包括:
try-with-resources: 管理需要显式关闭的资源(如 I/O 流、网络套接字、数据库连接)的标准方法。java.lang.ref.Cleaner(Java 9+): 一种更可靠、更灵活的机制,用于在对象变得不可达时注册清理操作。
接下来是什么?
Section titled “接下来是什么?”方法是 Java 程序的“主力”。理解如何定义、调用和组织它们至关重要。接下来的章节将探讨基于方法和类的更高级概念,首先是如何使用 Java 异常处理错误。