7.2 字段、方法与 this
前置知识:类、对象、引用变量和方法
预计时间:25 分钟
完成标志:能让对象的方法维护自身状态,并能解释
this与 Java 值传递
1. 实例方法操作当前对象的状态
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;
}
}调用实例方法需要一个接收者:
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());
}
}输出:
true
false
Java 核心技术,借出状态:true第二次借阅返回 false,没有制造“重复借出”的状态。也可以选择抛 IllegalStateException,但同一个类应保持一致契约。
调用 book.borrow() 时,book 是接收者。方法体在该对象上运行,因此能直接访问它的实例字段。若接收者为 null,方法体不会开始执行,而是抛 NullPointerException。
2. this 表示当前接收者
参数名与字段名相同时,未限定的名字优先指参数:
class Student {
String name;
void rename(String name) {
this.name = name;
}
}this.name 是当前对象的字段,右侧 name 是参数。没有冲突时,this 通常可以省略:
boolean isBorrowed() {
return borrowed;
}this 不是一个可重新赋值的普通变量,也不能出现在 static 上下文,因为静态方法没有当前对象。构造方法中的 this(...) 是另一种语法,用于调用同类其他构造方法,下一篇详讲。
3. 方法调用始终按值传递实参
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 可以形成流式调用,但不要滥用
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. 字段与局部变量的生命周期不同
实例字段随对象存在并有默认值。方法参数和局部变量只属于一次方法调用,必须先明确赋值才能读取。不要因为同名就把它们当成同一个存储位置。
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 两侧也要分别指出字段与参数。