跳到内容

第 1 卷 / 第 7 章 / 第 2 课

7.2 字段、方法与 this ​

前置知识:类、对象、引用变量和方法

预计时间:25 分钟

完成标志:能让对象的方法维护自身状态,并能解释 this 与 Java 值传递

1. 实例方法操作当前对象的状态 ​

java
class Book {
    String title;
    boolean borrowed;

    boolean borrow() {
        if (borrowed) {
            return false;
        }
        borrowed = true;
        return true;
    }

    boolean returnBook() {
        if (!borrowed) {
            return false;
        }
        borrowed = false;
        return true;
    }

    String description() {
        return title + ",借出状态:" + borrowed;
    }
}

调用实例方法需要一个接收者:

java
public class Library {
    public static void main(String[] args) {
        Book book = new Book();
        book.title = "Java 核心技术";

        System.out.println(book.borrow());
        System.out.println(book.borrow());
        System.out.println(book.description());
    }
}

输出:

text
true
false
Java 核心技术,借出状态:true

第二次借阅返回 false,没有制造“重复借出”的状态。也可以选择抛 IllegalStateException,但同一个类应保持一致契约。

调用 book.borrow() 时,book 是接收者。方法体在该对象上运行,因此能直接访问它的实例字段。若接收者为 null,方法体不会开始执行,而是抛 NullPointerException。

2. this 表示当前接收者 ​

参数名与字段名相同时,未限定的名字优先指参数:

java
class Student {
    String name;

    void rename(String name) {
        this.name = name;
    }
}

this.name 是当前对象的字段,右侧 name 是参数。没有冲突时,this 通常可以省略:

java
boolean isBorrowed() {
    return borrowed;
}

this 不是一个可重新赋值的普通变量,也不能出现在 static 上下文,因为静态方法没有当前对象。构造方法中的 this(...) 是另一种语法,用于调用同类其他构造方法,下一篇详讲。

3. 方法调用始终按值传递实参 ​

java
static void rename(Book book) {
    book.title = "新书名";
}

static void replace(Book book) {
    book = new Book();
    book.title = "局部对象";
}

调用 rename(original) 和 replace(original) 时,形参各得到 original 引用值的一份副本:

  • rename 通过副本找到同一个对象并修改字段,调用方能观察到。
  • replace 只给局部形参赋了新引用,调用方变量没有改变。

Java 没有“基本类型按值、对象按引用”这两套参数规则。只有一条规则:实参表达式的值被复制给形参;对象场景中,这个值恰好是引用值。

4. 返回 this 可以形成流式调用,但不要滥用 ​

java
class ReadingProgress {
    private int page;

    ReadingProgress moveTo(int page) {
        if (page < 0) {
            throw new IllegalArgumentException("negative page");
        }
        this.page = page;
        return this;
    }

    int page() {
        return page;
    }
}

调用者可以写 progress.moveTo(10).moveTo(20)。这适合配置器和构建器,但业务命令若失败策略复杂,逐条调用通常更清楚。

5. 字段与局部变量的生命周期不同 ​

实例字段随对象存在并有默认值。方法参数和局部变量只属于一次方法调用,必须先明确赋值才能读取。不要因为同名就把它们当成同一个存储位置。

java
class Counter {
    int total; // 新对象中默认为 0

    void add(int amount) { // amount 属于本次调用
        int previous = total; // previous 也是局部变量
        total = Math.addExact(previous, amount);
    }
}

这里的字段是包级可见,同包代码可以直接修改它们并绕过方法规则。当前示例为了先理解对象行为保持简单,封装篇会把字段改为 private,并只公开必要操作。

专业速查 ​

问题结论
实例方法操作谁调用表达式的接收者对象
this 是谁当前接收者
null 接收者方法体开始前抛 NullPointerException
对象参数传什么引用值的副本
给形参重新赋值不替换调用方变量
修改形参所指对象共享别名可观察到

离开这一页前 ​

让同一本书连续执行两次 borrow 和两次 returnBook,确认非法状态不会悄悄出现。再用一张引用图解释 rename(original) 会改共享对象,而 replace(original) 只重写形参副本;this.name = name 两侧也要分别指出字段与参数。

→ 下一步:构造方法与对象不变量

Built with VitePress | Software Systems Atlas