源本科技 | 码上会

Java 方法入门

2025/12/25
75
0

学习目标

  • 理解 Java 中方法的基本概念与作用

  • 掌握方法的声明语法与组成部分

  • 区分实例方法与静态方法的使用场景

  • 了解方法调用栈(Call Stack)的工作原理

  • 熟悉不同种类方法(预定义、用户自定义、抽象、静态)的调用方式


什么是 Java 方法?

Java 方法是执行特定任务的代码块。通过方法,我们可以复用代码,提升程序的效率组织性。在 Java 中,所有方法必须属于某个类。方法类似于其他语言中的“函数”,用于暴露对象的行为

示例:创建并调用一个简单方法

public class Example {
    // 定义一个方法
    public void printMessage() {
        System.out.println("Hello, World!");
    }
    
    public static void main(String[] args) {
        // 创建类的实例
        Example obj = new Example();
        
        // 调用方法
        obj.printMessage(); 
    }
}

输出:

Hello, World!

说明:

  • printMessage() 是一个无参数、无返回值的方法。

  • 使用 void 表示该方法不返回任何值。

  • 必须先创建对象,再通过对象调用非静态方法。


方法的语法结构

一个完整的 Java 方法声明包含以下关键组件:

组件

说明

访问修饰符

publicprivate,控制方法的可见性

返回类型

方法返回的数据类型(如 intString),若无返回值则为 void

方法名

遵循 camelCase 命名规范,通常以动词开头

参数列表

可选,括号内定义输入参数(类型 + 名称)

方法体

花括号 {} 内包含具体逻辑

public int add(int a, int b) {
    return a + b;
}

方法签名(Method Signature) 仅包含:方法名 + 参数列表(参数数量、类型、顺序)。

❌ 返回类型和异常不属于方法签名。


为什么使用方法?

将代码拆分为多个方法具有以下优势:

  • 代码复用性:一次编写,多次调用,避免重复代码

  • 模块化:每个方法专注单一职责,逻辑清晰

  • 可读性:命名良好的方法使代码更易理解

  • 可维护性:修改或调试只需关注特定方法,不影响整体结构


方法调用栈机制

Java 是基于栈(Stack) 的面向对象语言。当方法被调用时,JVM 使用 调用栈(Call Stack) 管理执行流程。

调用栈工作原理

  • 调用栈是一种 LIFO(后进先出) 的数据结构

  • 每次调用方法时,JVM 会:

    1. 在栈顶压入(push) 一个新的栈帧(Stack Frame)

    2. 栈帧中保存:局部变量、参数、返回地址等

    3. 方法执行完毕后,弹出(pop) 该栈帧,控制权返回上层调用者

示例:理解调用栈

public class CallStackExample {
    public static void D() {
        System.out.println("In Method D");
    }

    public static void C() {
        System.out.println("In Method C");
    }

    public static void B() {
        C(); // 调用 C
        System.out.println("In Method B");
    }

    public static void A() {
        B(); // 调用 B
        System.out.println("In Method A");
    }

    public static void main(String[] args) {
        A(); // 入口:调用 A
        D(); // 再调用 D
    }
}

输出:

In Method C
In Method B
In Method A
In Method D

JVM 自动管理整个调用栈,开发者无需手动操作。


Java 中的方法类型

1. 预定义方法

由 Java 标准库提供,可直接调用。

Math.random();  // 返回 0.0 ~ 1.0 之间的随机数
Math.PI;        // 返回圆周率 π ≈ 3.14159
"Hello".length(); // 字符串长度方法

2. 用户自定义方法

由程序员根据需求编写。

void greet() {
    System.out.println("Welcome!");
}

创建方法的两种方式

类型

特点

调用方式

实例方法

属于对象,可访问实例变量

通过对象调用:obj.method()

静态方法

属于类本身,用 static 修饰

通过类名调用:ClassName.method()

实例方法示例

class Calculator {
    void multiply(int a, int b) {
        System.out.println(a * b);
    }
}
// 调用:new Calculator().multiply(3, 4);

静态方法示例

class MathUtils {
    static int square(int x) {
        return x * x;
    }
}
// 调用:MathUtils.square(5);

方法命名规范

  • 方法名应为动词动词短语

  • 单词首字母小写,后续单词首字母大写(camelCase

  • 示例:

    • getName()

    • calculateTotalPrice()

    • isValid()

⚠️ 同一类中方法名必须唯一(除非使用方法重载


调用不同类型的方法

1. 调用自定义方法

class Greeter {
    void sayHello() {
        System.out.println("Hello from user-defined method!");
    }

    public static void main(String[] args) {
        Greeter g = new Greeter();
        g.sayHello(); // 通过对象调用
    }
}

2. 调用抽象方法

抽象方法无方法体,必须在子类中实现。

abstract class Animal {
    abstract void makeSound(); // 抽象方法
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Woof!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        myDog.makeSound(); // 输出:Woof!
    }
}

3. 调用预定义方法

public class Example {
    public static void main(String[] args) {
        Example obj = new Example();
        System.out.println(obj.hashCode()); // 调用 Object 类的预定义方法
    }
}
// 输出:类似 1510467688 的整数(对象哈希码)

4. 调用静态方法

class Utility {
    static void log(String msg) {
        System.out.println("[LOG] " + msg);
    }
}

public class App {
    public static void main(String[] args) {
        Utility.log("Program started"); // 无需创建对象
    }
}
// 输出:[LOG] Program started

重点总结

  • 方法是 Java 程序的基本构建单元,用于封装可复用逻辑

  • 所有方法必须定义在类中

  • 方法签名 = 方法名 + 参数列表(不含返回类型)

  • 实例方法需通过对象调用,静态方法可通过类名直接调用

  • JVM 使用调用栈自动管理方法的执行与返回

  • 合理使用方法能显著提升代码的可读性、可维护性与复用性


思考题

  1. 为什么 Java 不允许在类外部定义方法?这与 C/C++ 有何不同?

  2. 如果一个方法既需要访问实例变量,又希望被 main 方法直接调用,应该如何设计?

  3. 在调用栈中,如果递归调用过深会发生什么?如何避免?