Java | オブジェクト指向:this キーワード

Java Java
スポンサーリンク

this の全体像

this は「今まさに動いている、そのオブジェクト自身」を指すキーワードです。インスタンスメソッドやコンストラクタの中で使えて、フィールドへのアクセス、他のコンストラクタの呼び出し、メソッドチェーンの返り値などで登場します。読みやすさと安全性のために、this で「どのオブジェクトの状態を触っているか」を明示できるのが本質です。


フィールドとローカル変数の区別(シャドーイングの解消)

フィールド名と引数名が同じときの this

コンストラクタやメソッド引数がフィールドと同じ名前だと、ローカルが優先されます。this を付けると「フィールド側」を確実に指せます。

public final class Point {
    private int x, y;
    public Point(int x, int y) {
        this.x = x;  // フィールドへ代入
        this.y = y;
    }
    public void move(int dx, int dy) {
        this.x += dx;
        this.y += dy;
    }
}
Java

読みやすさのための this

フィールドを操作する行は、this を付けておくと「インスタンスの状態を触っている」ことが一目でわかります。ローカル変数と混在する場面で特に効果的です。

public void rename(String newName) {
    String trimmed = newName == null ? "" : newName.trim();
    if (!trimmed.isEmpty()) this.name = trimmed; // フィールド更新だと明示
}
Java

コンストラクタ連鎖と this()

別のコンストラクタへ委譲する this()

同じクラス内の他のコンストラクタを呼ぶときは、先頭で this(…) を使います。初期化ロジックを一箇所に集約でき、重複が消えます。

public final class User {
    private final String id;
    private final String name;

    public User(String id, String name) {
        if (id == null || id.isBlank()) throw new IllegalArgumentException("id");
        this.id = id;
        this.name = name == null ? "" : name.trim();
    }
    public User(String id) { this(id, ""); }      // 既定値へ委譲
    public User() { this("UNKNOWN", ""); }        // さらに既定値へ委譲
}
Java

this() と super() の順序

コンストラクタの先頭でしか使えません。継承時は super(…) か this(…) のいずれかが必ず最初の文で、両方は書けません。共通化したいなら子の this(…) → その呼び先で super(…) のように設計を整理します。


メソッドチェーンと this を返す

可変オブジェクトの Fluent API

setter 系を this を返すように定義すると、連鎖で読みやすく書けます。最後に build() などで確定する形が定番です。

public final class MailBuilder {
    private String to, subject, body;
    public MailBuilder to(String v) { this.to = v; return this; }
    public MailBuilder subject(String v) { this.subject = v; return this; }
    public MailBuilder body(String v) { this.body = v; return this; }
    public Mail build() { return new Mail(to, subject, body); }
}
var mail = new MailBuilder().to("a@b").subject("Hi").body("Hello").build();
Java

equals での this の使い方

同一インスタンスかの早期判定に使えます。パフォーマンスと正確さのための慣用句です。

@Override public boolean equals(Object o) {
    if (this == o) return true;               // まず同一性チェック
    if (!(o instanceof User u)) return false;
    return id.equals(u.id) && name.equals(u.name);
}
Java

スコープごとの this の意味(重要ポイントの深掘り)

インスタンスメソッド・コンストラクタでの this

「そのインスタンス自身」を指します。フィールドやメソッド呼び出しのレシーバとして使えます。

public int area() { return this.w * this.h; } // 明示的に書いても同じ意味
Java

static 文脈では this は使えない

static メソッドや static 初期化子には「インスタンス」が存在しないため、this は不使用です。必要なら引数でインスタンスを受け取る設計にします。

public static void print(User u) { System.out.println(u.name()); } // u で受ける
Java

内部クラス・外側の this の指定

ネストしたクラスで「外側のインスタンス」を指したいときは、外側名.this を使います。

class Outer {
    private final String name = "outer";
    class Inner {
        void say() { System.out.println(Outer.this.name); } // 外側のフィールドへ
    }
}
Java

ラムダ式と this

ラムダ内の this は「ラムダ自身」ではなく、囲んでいるクラスのインスタンスを指します。匿名クラスとは挙動が異なるので注意。

class Greeter {
    private final String prefix = "Hi";
    Runnable r = () -> System.out.println(this.prefix); // Greeter の this
}
Java

実用例で身につける

例 1: シャドーイング回避と読みやすさ

public final class Product {
    private String name;
    private int price;

    public void reprice(int price) {
        if (price >= 0) this.price = price; // フィールド更新を明示
    }
    public void rename(String name) {
        var x = name == null ? "" : name.trim();
        if (!x.isEmpty()) this.name = x;
    }
}
Java

例 2: this() で既定値へ委譲

public final class Config {
    private final String region;
    private final int timeoutMs;

    public Config(String region, int timeoutMs) {
        if (region == null || region.isBlank()) throw new IllegalArgumentException();
        if (timeoutMs <= 0) throw new IllegalArgumentException();
        this.region = region;
        this.timeoutMs = timeoutMs;
    }
    public Config() { this("ap-northeast-1", 3000); }
}
Java

例 3: this を返してチェーン

public final class Query {
    private String table, where;
    public Query table(String t) { this.table = t; return this; }
    public Query where(String w) { this.where = w; return this; }
    public String build() { return "SELECT * FROM " + table + (where == null ? "" : " WHERE " + where); }
}
var sql = new Query().table("users").where("active=1").build();
Java

例 4: 外側の this を指定

class Window {
    private String title = "Main";
    class Button {
        void click() { System.out.println(Window.this.title + " clicked"); }
    }
}
Java

よくあるつまずきと回避

static で this を使おうとしてエラー

static には「今のインスタンス」がありません。必要ならインスタンスを引数で受けるか、インスタンスメソッドへ移すのが正解です。

コンストラクタで this() と super() を両方書く

先頭にはどちらか一方のみ。親の初期化が必要なら、委譲先のコンストラクタで super(…) を呼ぶ設計に整理します。

ラムダの this を誤解

ラムダ内の this は囲んでいるクラスのインスタンス。匿名クラスの this(その匿名クラス自身)と混同しないようにしましょう。


仕上げのアドバイス(重要部分のまとめ)

this は「今のインスタンス」を指す合図。フィールドと引数の区別を明確にし、チェーンでは this を返して読みやすさを上げる。コンストラクタの委譲は this(…) で重複を消し、継承時の初期化は super(…) を先頭で。static 文脈では使えず、内部クラスやラムダでの意味の違いを押さえる——この感覚が身につくと、状態操作の曖昧さが消え、設計とコードがすっきりします。

タイトルとURLをコピーしました