this 关键字
本教程共 100 篇 · 第 34 篇 · 更新于 2026-08-05 · 约 14 分钟阅读
34. this 关键字
本节目标:理解 this 代表”当前对象自己”,学会用它区分同名的成员变量和局部变量、在构造里调用其他构造、把当前对象传给别处。
this 翻译过来就是”这个”。在 Java 里,它指代当前正在调用方法的那个对象。谁调用,this 就是谁。
this 指代当前对象
public class Student {
String name;
void show() {
System.out.println(this.name); // this 指调用 show 的那个学生
}
}
```bash
`s1.show()` 时,this 就是 s1;`s2.show()` 时,this 就是 s2。所以 this 让方法知道"我属于哪个对象"。
> [!NOTE]
> 同一个方法被不同对象调用,this 指向就不同。这就是为什么每个对象能维护自己的状态——方法里操作的都是"当前对象"的数据。
## 区分同名变量
最常见用法:局部变量(通常是构造/方法的参数)和成员变量同名时,用 this 指成员变量。
```java
public class Student {
String name;
Student(String name) { // 参数也叫 name
this.name = name; // this.name 是成员变量,右边 name 是参数
}
}
不加 this,name = name 会把参数赋给参数自己,成员变量纹丝不动。这种写法在构造方法里天天见。
Warning形参名和成员变量同名是推荐写法(可读性好),但一定要用
this.点明成员变量,否则赋值无效。忘了 this 是初学者高频 bug。
方法里也能用 this
不只是构造方法,普通方法里参数和成员变量同名时也能用:
public class Student {
String name;
void setName(String name) {
this.name = name; // 左边成员变量,右边参数
}
}
```bash
## this 调用其他构造:this()
同一个类里,用 `this(参数)` 调用另一个构造方法,必须放在构造体第一行。
```java
public class Student {
String name;
int age;
Student() {
this("未知"); // 调用单参构造
}
Student(String name) {
this(name, 0); // 调用双参构造
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
}
这样三个构造串成一条链,真正的赋值逻辑只在最后那个写一遍。
Note
this()和this.属性都基于”当前对象”这个语义。前者省去重复写构造代码,后者解决命名冲突。记住一句话:this 就是”我这个对象”。
this() 的规则
- 必须放在构造方法的第一行
- 不能循环调用:A 调 B,B 又调 A,编译报错
- 一个构造方法里只能调一次 this()
this()和super()不能同时出现在同一个构造方法里(都要求第一行)
// 错的示范:循环调用
Student() {
this("x"); // 调第二个
}
Student(String name) {
this(); // 又调第一个,循环!编译报错
}
```bash
## 把当前对象传出去
有时需要把"自己"传给别的方法,比如注册监听器:
```java
void register() {
someService.addListener(this); // 把当前对象作为监听者传过去
}
这种”把自己交出去”的写法在事件处理、回调里很常见。
Warning构造方法里不要急着把 this 传出去。对象还没构造完,外部就可能开始使用它,读到半初始化的状态。这是线程安全的隐患。建议构造完成后再注册或传递。
Tip不用 this 也能跑的代码,就不必硬加 this(除了解决重名)。滥用 this 反而让代码变啰嗦。它的核心价值就两点:区分重名、串构造。
this 在 equals 里
重写 equals 方法时,this 代表当前对象,参数是另一个对象:
public class Student {
String name;
int age;
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // 同一个对象,直接相等
if (!(obj instanceof Student)) return false;
Student other = (Student) obj;
return this.age == other.age && this.name.equals(other.name);
}
}
```bash
`this == obj` 先判断是不是同一个引用,是的话直接返回 true,省去逐字段比较。
## this 在 compareTo 里
实现 Comparable 接口时,this 是当前对象,参数是另一个:
```java
public class Student implements Comparable<Student> {
int score;
@Override
public int compareTo(Student other) {
return this.score - other.score; // 按分数升序
}
}
this 在内部类里
内部类里 this 指内部类对象本身。如果想访问外部类的 this,用 外部类名.this:
public class Outer {
String name = "外部";
class Inner {
String name = "内部";
void show() {
System.out.println(name); // 内部
System.out.println(this.name); // 内部
System.out.println(Outer.this.name); // 外部
}
}
}
```bash
## this 在 record 里(Java 16+)
record 是 Java 16 引入的不可变数据载体。this 在 record 里同样指当前实例:
```java
public record Point(int x, int y) {
double distanceToOrigin() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
}
record 的字段默认 private final,this 访问它们和普通类一样。
this 在 switch 表达式里(Java 21+)
Java 21 引入了 switch 的 arrow 形式,this 的使用没有变化。但有个细节要注意——lambda 里的 this 和匿名内部类的 this 不一样:
public class Demo {
String name = "demo";
void testLambda() {
Runnable r = () -> {
System.out.println(this.name); // 指外部类 Demo
};
}
void testAnonymous() {
Runnable r = new Runnable() {
String name = "inner";
@Override
public void run() {
System.out.println(this.name); // 指匿名类自己
}
};
}
}
```bash
lambda 里的 this 指向包含 lambda 的外部类,匿名内部类的 this 指向匿名类自己。这是常见面试坑。
## this 在枚举里
枚举常量可以有自己的方法,this 指向当前枚举常量:
```java
public enum Color {
RED("#FF0000"),
GREEN("#00FF00"),
BLUE("#0000FF");
private final String hex;
Color(String hex) {
this.hex = hex;
}
public String getHex() {
return this.hex; // 返回当前枚举常量的 hex
}
}
this 在密封类里(Java 17+)
密封类(sealed class)控制谁能继承它。this 在密封类里的行为和普通类一样:
public sealed class Shape permits Circle, Rectangle {
double area() {
return switch (this) { // Java 21+ 的 pattern matching
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
};
}
}
```bash
## this 在方法链式调用里的应用
Builder 模式是 this 返回的经典场景:
```java
public class HttpClient {
private String url;
private int timeout;
public HttpClient url(String url) {
this.url = url;
return this; // 返回当前对象,支持链式调用
}
public HttpClient timeout(int timeout) {
this.timeout = timeout;
return this;
}
}
// 使用:链式调用,一气呵成
new HttpClient().url("https://example.com").timeout(5000);
每个 setter 返回 this,就能连续调用。这是 this 在实际工程里的高频用法。
this 与线程安全
this 本身不涉及线程安全,但”把 this 传出去”要注意:对象还没构造完就把 this 传给其他线程,可能看到半初始化的状态。
public class Student {
String name;
Student(String name) {
this.name = name;
GlobalEventBus.register(this); // 危险!对象还没构造完
}
}
```bash
构造方法里把 this 传给外部,外部可能在构造完成前就用这个对象,读到不完整的状态。建议构造完成后再注册。
## this 在函数式接口里的陷阱
lambda 表达式里 this 指向外部类,这会导致一个常见陷阱——在 lambda 里调用 `this.equals()` 实际调用的是外部类的 equals,而不是 lambda 自身:
```java
public class Demo {
void test() {
Runnable r = () -> {
// this 指 Demo 实例,不是 Runnable 实例
System.out.println(this.getClass()); // class Demo
};
}
}
如果需要在匿名内部类里访问自身,直接用 this;如果要访问外部类的 this,用 外部类名.this。
速查表
| 用法 | 写法 | 场景 |
|---|---|---|
| 访问成员变量 | this.name | 区分同名参数 |
| 调用其他构造 | this(参数) | 构造链,必须第一行 |
| 传当前对象 | method(this) | 监听器、回调 |
| 判断同一引用 | this == obj | equals 开头 |
| 外部类 this | Outer.this | 内部类访问外部 |
| 返回当前对象 | return this | 链式调用 Builder |
| 枚举方法内 | this.hex | 访问当前枚举常量 |
常见疑问
Q:静态方法里能用 this 吗? 不能。静态方法属于类,不依赖对象,没有”当前对象”的概念。静态方法里写 this 会编译报错。
Q:this 能当返回值吗?
能。return this 返回当前对象,常用于”链式调用”(Builder 模式)。比如 new Builder().setA(1).setB(2).build(),每个 setter 都返回 this。
Q:lambda 表达式里 this 指什么? lambda 里的 this 和外面方法里的 this 一样,指包含 lambda 的对象实例。这点和匿名内部类不同——匿名内部类的 this 指匿名类自己。
Q:构造方法里 this() 和 this. 能同时用吗?
不能。this() 必须放在构造方法第一行,后面不能再有 this()。但 this() 调用之后可以用 this.属性 给成员变量赋值。比如 this("未知"); this.age = 0; 是合法的。
Q:this 能当参数传给父类构造吗?
不能。super() 必须放在构造方法第一行,this() 也必须放第一行,两者冲突。所以不能在 super() 之前或之后用 this(),也不能把 this 传给 super()。
Q:this 在泛型类里能用吗?
能。泛型类的 this 和普通类一样,指当前实例。泛型类型参数不影响 this 的语义。比如 Box<T> { void set(T val) { this.value = val; } } 完全合法。