`this` 是 Java 最基礎又最易誤用的關鍵字。本文結合 Android 開發中經典的 Handler 持有外部 Activity 引用導致內存洩漏 案例,深度解析 `this` 在匿名內部類、Lambda、內部類中的指向差異,並給出生產級解決方案。
| 上下文 | this 指向 | 示例 |
|---|---|---|
| 實例方法 | 調用該方法的對象實例 | `user.setName("A")` 中 `this` = `user` |
| 構造器 | 正在構造的對象 | `this(name)` 調用另一構造器 |
| 普通內部類 | 內部類實例本身 | `OuterClass.this` 訪問外部類 |
| 匿名內部類 | 匿名類實例本身 | `new Runnable() { this }` = Runnable 實例 |
| Lambda 表達式 | 外層實例(詞法作用域) | `() -> this` = 外部類實例 |
public class MainActivity extends Activity {
private TextView result;
private EditText input;
private Handler handler = new Handler() { // ❌ 匿名內部類隱式持有 MainActivity.this
@Override
public void handleMessage(Message msg) {
result.setText("Updated: " + msg.getData().getString("data"));
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
result = findViewById(R.id.result);
input = findViewById(R.id.input);
findViewById(R.id.update).setOnClickListener(v -> {
new Thread(() -> {
Message msg = Message.obtain();
msg.getData().putString("data", input.getText().toString());
handler.sendMessage(msg); // 發送消息到主線程
}).start();
});
}
}
| 方案 | 代碼關鍵點 | 優點 | 缺點 |
|---|---|---|---|
| 靜態內部類 + WeakReference | static class MyHandler extends Handler { WeakReference<Activity> ref; } | 徹底切斷強引用、標準模式 | 代碼稍繁瑣 |
| onDestroy 移除消息 | handler.removeCallbacksAndMessages(null) | 簡單、無需改結構 | 若消息已分發執行中無效、易忘 |
| Lambda + 靜態 Handler | static Handler handler = new Handler(Looper.getMainLooper(), msg -> { ... }) | Java 8+ 簡潔、無外部引用 | 需 API 24+ 或插糖 |
| Lifecycle/ViewModel + LiveData/Flow | 架構組件自動生命周期感知 | 現代最佳實踐、零洩漏 | 需遷移架構 |
public class MainActivity extends AppCompatActivity {
private TextView result;
private EditText input;
// 靜態內部類:不持有外部類引用
private static class UiHandler extends Handler {
private final WeakReference activityRef;
UiHandler(MainActivity activity) {
this.activityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(@NonNull Message msg) {
MainActivity activity = activityRef.get();
if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
return; // Activity 已銷毀,放棄處理
}
// 安全訪問 View
String data = msg.getData().getString("data");
activity.result.setText("Updated: " + data);
}
}
private final Handler handler = new UiHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
result = findViewById(R.id.result);
input = findViewById(R.id.input);
findViewById(R.id.update).setOnClickListener(v -> {
new Thread(() -> {
Message msg = Message.obtain();
msg.getData().putString("data", input.getText().toString());
handler.sendMessage(msg);
}).start();
});
}
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null); // 雙重保險
}
}
public class ThisDemo {
private String name = "Outer";
public void test() {
// 匿名內部類:this = 匿名類實例
Runnable anon = new Runnable() {
@Override public void run() {
System.out.println("Anonymous this: " + this); // ThisDemo$1@...
System.out.println("Outer via ThisDemo.this: " + ThisDemo.this.name);
}
};
// Lambda:this = 外部實例(詞法捕獲)
Runnable lambda = () -> {
System.out.println("Lambda this: " + this); // ThisDemo@...
System.out.println("Lambda this.name: " + this.name); // Outer
};
anon.run();
lambda.run();
}
public static void main(String[] args) {
new ThisDemo().test();
}
}
理解 `this` 在不同語境下的指向,是寫出無洩漏 Java/Android 代碼的關鍵。從今日起,拒絕在長壽命對象中直接 `new Handler() {}`,擁抱靜態內部類、WeakReference 與架構組件。