首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

深入理解 Java this 關鍵字:三大核心用法與構造器鏈機制

     編輯:Java 相關知識

this 三大標準用法

1. 代表當前實例 (最常用)

public class Person {
    private String name;
    
    public void setName(String name) {
        this.name = name; // 區分字段與參數
    }
    
    public Person self() {
        return this; // 返回當前對象引用,支援鏈式調用
    }
}

用於:字段/參數同名消歧義、返回當前對象、傳遞當前對象給其他方法。

2. 調用本類其他構造器 (構造器鏈)

public class Point {
    private int x, y;
    private String label;
    
    public Point() {
        this(0, 0); // 必須是構造器第一條語句
    }
    
    public Point(int x, int y) {
        this(x, y, "origin"); // 呼叫三參構造器
    }
    
    public Point(int x, int y, String label) {
        this.x = x;
        this.y = y;
        this.label = label;
    }
}

規則:this(...) 必須置於構造器首行;一個構造器只能調用一個 this(...);不能與 super(...) 共存。

3. 內部類引用外部類實例

public class Outer {
    private int value = 10;
    
    public class Inner {
        public void print() {
            System.out.println(Outer.this.value); // 訪問外部類字段
            System.out.println(this.value);       // 訪問內部類字段 (若存在)
        }
    }
}

進階場景:構造器中傳遞 this 的隱患

常見模式:構造器註冊監聽器/回調

public class EventSource {
    private List listeners = new ArrayList<>();
    
    public void addListener(Listener l) { listeners.add(l); }
    public void removeListener(Listener l) { listeners.remove(l); }
    
    protected void fireEvent() {
        for (Listener l : listeners) l.onEvent(this);
    }
}

public class MyComponent implements Listener {
    private final EventSource source;
    
    public MyComponent(EventSource source) {
        this.source = source;
        source.addListener(this); // 構造器中傳遞 this!
    }
    
    @Override public void onEvent(Object src) { ... }
}

核心風險:this 逃逸

在構造器完成前,對象 尚未完全初始化 (字段可能為默認值、不變量未建立)。若 this 被發布 (存入集合、註冊監聽、啟動線程),其他執行緒/代碼可能看到 部分構造狀態,導致不可預期錯誤。

安全替代方案

  1. 工廠方法 + 兩階段初始化:
    public static MyComponent create(EventSource source) {
        MyComponent comp = new MyComponent();
        comp.init(source); // 完全構造後註冊
        return comp;
    }
    
    private MyComponent() {} // 私有構造器
    
    private void init(EventSource source) {
        this.source = source;
        source.addListener(this);
    }
  2. 構造器不註冊,提供显式 init()/start() 方法:調用者負責調用
  3. 使用初始化塊:仍在構造器內,風險同在

構造器鏈與超類初始化順序深度解析

初始化完整順序

  1. 父類靜態字段/靜態塊 (按聲明順序)
  2. 子類靜態字段/靜態塊
  3. 父類實例字段/實例初始化塊
  4. 父類構造器 (super() 顯式或隱式調用)
  5. 子類實例字段/實例初始化塊
  6. 子類構造器 (this(...) 鏈最終到達的構造器體)

驗證代碼

class Parent {
    Parent() { System.out.println("Parent()"); }
}
class Child extends Parent {
    Child() { this(10); System.out.println("Child()"); }
    Child(int x) { System.out.println("Child(int)"); }
}
new Child();
// 輸出:
// Parent()
// Child(int)
// Child()

關鍵點:Child() 調用 this(10),Child(int) 隱式調用 super(),故先執行父構造器。

this 在並發環境下的特殊語義

final 字段與 this 發布

public class SafePublish {
    private final int value; // final 字段
    
    public SafePublish(int v) {
        value = v;
        // 此處 this 逃逸安全:JMM 保證 final 字段寫入對其他線程可見
        // 前提:構造器內未發布 this (或僅發布給不依賴 final 字段的代碼)
    }
}

JMM (Java Memory Model) 保證:正確構造的對象 (無 this 逃逸),其 final 字段在構造器結束前的寫入,對所有線程可見,無需同步。

總結與最佳實踐

場景建議
字段/參數同名必加 this. 消歧義
構造器鏈善用 this(...) 減少重複代碼
內部類訪問外部使用 OuterClass.this
構造器中傳遞 this極力避免;改用工廠/兩階段初始化
並發環境構造所有字段 final + 無 this 逃逸 = 安全發布
方法鏈式調用返回 this 實現流暢 API

this 看似簡單,實則涉及 對象構造生命週期、內存可見性、封裝邊界 等核心機制。理解「構造器中 this 逃逸」風險,是從初級進階為高級 Java 開發者的關鍵門檻之一。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved