方法
什么是方法?
在 Java 中,方法(Method)是类中定义的一段代码块,用于执行特定的功能或任务。它是程序中可重复使用的逻辑单元,通常用来完成某个操作或返回某个计算结果。方法是面向对象编程中实现封装和模块化的重要手段。
方法的特点
- 可重用性:方法可以在程序中多次调用,避免代码重复。
- 模块化:将复杂逻辑拆分成小块,便于维护和理解。
- 封装性:通过访问修饰符(如
public
、private
)控制方法的可访问范围,保护数据安全。
方法的定义
方法的定义通常包含以下部分:
java
修饰符 返回值类型 方法名(参数列表) {
// 方法体:执行的代码逻辑
return 返回值; // 如果返回值类型不是 void,则需要返回相应的值
}
组成说明:
- 修饰符:如
public
、private
、static
等,控制方法的访问权限和行为。public
:方法可被任意类访问。private
:方法仅在定义的类内部可访问。static
:表示方法属于类而非实例,无需创建对象即可调用。
- 返回值类型:方法执行后返回的数据类型,如
int
、String
或void
(无返回值)。 - 方法名:遵循命名规范,通常以动词开头,使用小驼峰命名法(如
calculateSum
)。 - 参数列表:方法接收的输入参数,可以为空或包含多个参数,格式为
(类型 参数名, 类型 参数名, ...)
。 - 方法体:方法的实际逻辑代码。
- return 语句:如果方法有返回值,必须使用
return
返回指定类型的值;void
方法可以省略return
或使用空return;
。
示例代码
以下是一个计算两个int类型的和的方法:
java
/**
* 求两个int类型的和
* @param a 参数a
* @param b 参数b
* @return 结果
*/
public int add(int a, int b) {
return a + b;
}
方法的分类
成员方法
成员方法又称实例方法,是类的一个成员,属于类的对象,可以通过对象来调用。
示例:
java
public class Calculator {
public static void main(String[] args) {
// 创建一个Calculator对象
Calculator calc = new Calculator();
// 调用成员方法
int result = calc.subtract(10, 5);
System.out.println(result);
}
// 成员方法
public int subtract(int a, int b) {
return a - b;
}
}
静态方法
使用 static
关键字修饰的方法,称为静态方法,属于类的方法,可以通过类名来调用,不需要创建对象。常用于工具类或不依赖实例状态的操作。
示例:
java
public class MathUtils {
public static void main(String[] args) {
// 不需要创建对象,直接通过类名称调用
int result = MathUtils.multiply(4, 5);
System.out.println(result);
}
// 静态方法
public static int multiply(int a, int b) {
return a * b;
}
}
构造方法
构造方法又称构造函数,是类的一个特殊的方法,用于创建和初始化对象的状态,方法名与类名相同,无返回值类型。自动在对象创建时调用(使用 new
关键字)。
示例:
java
public class Main {
public static void main(String[] args) {
// 创建 Student 对象
Student student = new Student("张三", 18);
// 没有重写toString()方法所以显示method.Student@30f39991
System.out.println(student);
}
}
// Student 类
class Student {
// 成员变量
String name;
Integer age;
// 构造方法
Student(String name, Integer age) {
this.name = name;
this.age = age;
}
}
方法的调用
调用方式
成员方法(实例方法):通过对象实例调用,格式为 对象名.方法名(参数列表)
。
静态方法(类方法):通过类名调用,格式为 类名.方法名(参数列表)
。
构造方法:使用 new
关键字创建对象,格式为 new 类名(参数列表)
。
示例:
java
public class Main {
public static void main(String[] args) {
// new关键字调用构造方法创建Example类的对象实例
Example e = new Example("haha");
e.instanceMethod(); // 输出:这是一个成员(实例)方法
Example.staticMethod(); // 输出:这是一个静态方法
}
}
// Example 类
class Example {
// 成员变量
String msg;
// 空参数的构造方法
public Example() {
}
// 有参数的构造方法
public Example(String m) {
this.msg = m;
}
// 成员方法
public void instanceMethod() {
System.out.println("这是一个成员(实例)方法");
}
// 静态方法
public static void staticMethod() {
System.out.println("这是一个静态方法");
}
}
形参和实参
形参(形式参数):方法定义时的参数,用于接收方法调用时传递的实参。
实参(实际参数):方法调用时传递的参数,用于替换形参的值。
示例:
java
public class Main {
public static void main(String[] args) {
// 调用方法时传递的10和5是实参
int result = add(10, 5);
System.out.println(result);
}
// 方法定义的参数a和b是形参
public static int add(int a, int b) {
return a + b;
}
}
参数传递
Java方法的参数传递只有一种方式:值传递。
- 对于基本数据类型(如
int
、double
):传递的是值的副本,方法内的修改不影响原值。 - 对于引用类型(如对象、数组):传递的是引用地址的副本,方法内可修改对象的属性,但不能改变原引用指向的对象。
示例:
java
public class Main {
public static void main(String[] args) {
int a = 1; // 变量 a 在 main 方法的栈帧中,存储的值就是 1
int b = 2; // 变量 b 在 main 方法的栈帧中,存储的值就是 2
test1(a, b); // 调用 test1 方法
// ... a 的值仍然是 1, b 的值仍然是 2
}
public static void test1(int a, int b) { // 注意:这里的 a 和 b 是 test1 方法的局部变量
// 当调用 test1(a, b) 时,发生了以下事情:
// 1. 在 test1 方法的栈帧中,创建了新的局部变量 a 和 b。
// 2. 将 main 方法中 a 的值 (1) 复制一份,赋给 test1 的变量 a。
// 3. 将 main 方法中 b 的值 (2) 复制一份,赋给 test1 的变量 b。
// 所以,此时存在两套 a 和 b,它们互不相干。
a = 100; // 这里修改的是 test1 方法栈帧中的 a,和 main 方法中的 a 没有任何关系。
b = 200; // 同理,修改的是 test1 方法中的 b。
}
}
java
public class Main {
public static void main(String[] args) {
// 1. new int[]{1, 2, 3, 4, 5} 在堆内存中创建了一个数组对象。
// 假设这个对象在内存中的地址是 0x123ABC。
// 2. int[] arr; 创建了一个引用变量 arr。
// 3. arr = ...; 将数组对象的地址 0x123ABC 赋值给了 arr。
// 所以,arr 变量中存储的“值”是 0x123ABC。
int[] arr = new int[]{1, 2, 3, 4, 5};
test1(arr); // 调用 test1 方法
}
public static void test1(int[] array) { // 注意:这里的 array 是 test1 方法的局部变量
// 当调用 test1(arr) 时,发生了什么?
// 同样是值传递!
// 1. 在 test1 方法的栈帧中,创建了新的局部变量 array。
// 2. 将 main 方法中 arr 的“值” (也就是地址 0x123ABC) 复制一份,赋给 test1 的变量 array。
// 现在,main 方法中的 arr 和 test1 方法中的 array,它们的值都是 0x123ABC。
// 这意味着它们都指向了堆内存中同一个数组对象。
// 就像你把房子的钥匙复制了一把给朋友,你们俩的钥匙都能打开同一扇门。
// 将第一个元素改成999
array[0] = 999;
// 这行代码的含义是:
// 1. 通过 array 变量中存储的地址 (0x123ABC) 找到堆内存中的数组对象。
// 2. 修改这个数组对象的第一个元素为 999。
// 因为 arr 和 array 指向的是同一个对象,所以当 test1 执行完毕后,
// 回到 main 方法,通过 arr 去查看那个数组对象时,会发现它已经被修改了。
}
}
方法重载
方法重载允许在同一类中定义多个同名方法,但参数列表(参数数量或类型)必须不同。Java 会根据调用时的参数类型和数量选择合适的方法。
方法重载的规则:
- 方法名必须相同。
- 参数列表不同(数量或者类型)。
- 返回值类型、修饰符不影响重载。
示例:
java
public class Printer {
public static void main(String[] args) {
// 调用方法
Printer printer = new Printer();
printer.print("Hello"); // 输出: String: Hello
printer.print(42); // 输出: Integer: 42
printer.print("Test", 100); // 输出: String and Integer: Test, 100
}
public void print(String s) {
System.out.println("String: " + s);
}
public void print(int i) {
System.out.println("Integer: " + i);
}
public void print(String s, int i) {
System.out.println("String and Integer: " + s + ", " + i);
}
}
注意事项
- 命名规范:方法名应使用小驼峰命名法,清晰表达功能,如 calculateArea、sendMessage。
- 单一职责:一个方法尽量只完成一个功能,避免逻辑过于复杂。
- 参数设计:避免过多参数,通常不超过 4 个;若参数过多,考虑使用对象封装。
- 异常处理:方法可能抛出异常,需使用 throws 声明或 try-catch 处理。
- 性能优化:避免在方法中执行过多计算或资源密集型操作,必要时优化算法。