IT・WEB・ゲーム業界の転職に強いR-Stone

転職コラム

Javaの「this」って?意味や基本的な使い方を解説

Javaのthisキーワードは、オブジェクト指向プログラミングにおいて重要な役割を果たす特別な参照です。現在のオブジェクトを指すthisを適切に使用すれば、コードの可読性と保守性を大幅に向上できます。

本記事では、thisの基本的な意味から実際のコードでの使用例まで、幅広く解説します。

メンバ変数とローカル変数の区別、コンストラクタでの使用、メソッドチェーンの実現など、thisの活用方法を学び、Javaプログラミングのスキル向上にお役立てください。

Javaの「this」とは?

Java言語の「this」キーワードは、現在のオブジェクトインスタンスを指す特別な参照です。thisはオブジェクト指向プログラミングで欠かせない役割があります。

「this」は、クラス内のメソッドやコンストラクタから、そのインスタンス自身を参照するために使われます。つまり、「this」を使うことで、コードが実行されているインスタンス自身にアクセスできます。

以下は「this」の基本的な使用例です:

public class 人物 {

    private String 名前;

 

    public void 名前を設定する(String 名前) {

        this.名前 = 名前;

    }

}

 

// 2人分の異なるインスタンスを作成

人物 person1 = new 人物();

人物 person2 = new 人物();

person1.名前を設定する(“花子”);

person2.名前を設定する(“太郎”);

上記コードでは、「this.名前」は個別のインスタンスの「名前」フィールドを指しています。

thisを使うメリット

「this」キーワードの主要なメリットは、クラスのメンバ変数(インスタンス変数)とローカル変数(メソッド内で宣言された変数)を明確に区別できることです。

特に、メソッドの引数名とクラスのフィールド名が同じ場合(シャドーイング)に有用です。

「シャドーイング」とは、ローカル変数がより広いスコープの変数(クラスのメンバ変数)と同じ名前を持つことで、広いスコープの変数が隠れてしまう現象を指します。

「this」キーワードを使用すると、シャドーイングの問題を簡単に解決できます。

public class Person {

    private String name;  // クラスのメンバ変数

 

    public void setName(String name) {  // 引数もnameという名前

        this.name = name;  // thisを使用してメンバ変数を明確に指定

    }

}

上記のコードでは、setNameメソッドの引数名とクラスのメンバ変数名が同じnameになっています。

thisキーワードにより「インスタンスのメンバ変数name」を明確に指し示せるため、メソッドの引数として渡されたnameの値をインスタンスのメンバ変数nameへ代入する意図が明確になり、他の開発者がコードを読んだ際にも理解しやすくなります。

thisを使える場面・使えない場面

「this」キーワードは特定の状況で使用でき、また使用できない場面もあります。

使える場面① インスタンスメソッド内

「this」は通常、インスタンスメソッド内で使用されます。現在のオブジェクトを参照するのに役立ちます。

public class 車 {

    private String 色;

 

    public void 色を設定(String 色) {

        this.色 = 色;

    }

}

使える場面② コンストラクタ内

コンストラクタ内で「this」を使用して、クラスのフィールドを初期化したり、他のコンストラクタを呼び出したりできます。

public class 車 {

    private String 色;

    private int 年式;

 

    public 車(String 色) {

        this(色, 2023);  // 別のコンストラクタを呼び出す

    }

 

    public 車(String 色, int 年式) {

        this.色 = 色;

        this.年式 = 年式;

    }

}

使えない場面 クラスメソッド・静的ブロック

クラスメソッドや静的ブロック内では「this」は使用できません。

クラスメソッドなど静的コードは特定のインスタンスに属さないため、thisの対象を特定できないのが理由です。

public class 車 {

    private static int 総台数;

 

    public static void 台数を増やす() { // クラスメソッド(静的メソッド)

        // this.総台数++;  // エラーになります。

        総台数++;  // 正しい使い方です。

    }

 

    public void 台数確認() {

        System.out.println(車.総台数);  // クラス名を付けてもよい

    }

}

 

// 使用例

車 car = new 車();

car.台数を増やす();

car.台数確認();     // 1を表示

Javaのthisの基本的な使い方

Javaの「this」キーワードは、現在のオブジェクトインスタンスを参照するために使用されます。主な用途として、メンバ変数とローカル変数の区別、コンストラクタの呼び出しなどで活用されます。

thisを適切に使用すれば、コードの可読性が向上し、オブジェクト指向プログラミングの原則に沿った効率的な実装が可能になります。また、名前の衝突を避け、コードの意図をより明確に表現できるメリットがあります。

メンバ変数とローカル変数の使い方

thisキーワードは、メンバ変数とローカル変数の名前が同じ場合に、両者を区別するために使用します。メソッドやコンストラクタ内で、thisを使ってメンバ変数を明示的に指定すれば、ローカル変数との混同を避けられます。

public class 人間 {

    private String 名前;

 

    public void 名前設定(String 名前) {

        this.名前 = 名前;  // thisを使用してメンバ変数を指定

    }

}

上記コード例では、メソッドの引数名とメンバ変数名が同じ「名前」ですが、thisを使用すると明確に区別できます。

コンストラクタを呼び出すときの使い方

thisキーワードは、同じクラス内の別のコンストラクタを呼び出すためにも使用されます。コンストラクタチェイニングと呼ばれる技法で、コードの重複を減らし、オブジェクトの初期化を効率的におこなえます。

以下は、thisを使用してコンストラクタを呼び出す例です。

public class 従業員 {

    private String 名前;

    private int 年齢;

 

    public 従業員(String 名前) {

        this(名前, 0);  // 別のコンストラクタを呼び出し

    }

 

    public 従業員(String 名前, int 年齢) {

        this.名前 = 名前;

        this.年齢 = 年齢;

    }

}

上記の例では、1つのコンストラクタが別のコンストラクタを呼び出し、共通の初期化ロジックを再利用しています。

コンストラクタを使い分けるときの使い方

thisを使用してコンストラクタを使い分けることで、オブジェクトの初期化を柔軟におこなえます。複数のコンストラクタを提供し、それぞれで異なる初期化処理をおこなうことができます。

public class 商品 {

    private String 名前;

    private double 価格;

    private int 在庫数;

 

    public 商品(String 名前) {

        this(名前, 0);

    }

 

    public 商品(String 名前, double 価格) {

        this(名前, 価格, 0);

    }

 

    public 商品(String 名前, double 価格, int 在庫数) {

        this.名前 = 名前;

        this.価格 = 価格;

        this.在庫数 = 在庫数;

    }

}

上記の例では、異なる引数を持つ複数のコンストラクタを提供し、柔軟なオブジェクト初期化を可能にしています。

その他の使い方について

thisには、基本的な使い方以外にもいくつかの応用があります。本項で紹介する使い方を理解すると、より柔軟なプログラミングが可能になります。

メソッドチェーン

thisキーワードには、メソッドチェーンを実現するための使い方もあります。メソッド内でthisを返すことで、複数のメソッド呼び出しを連鎖させることができます。

public class ビルダー {

    private StringBuilder 文字列ビルダー = new StringBuilder();

 

    public ビルダー 追加(String 文字列) {

        文字列ビルダー.append(文字列);

        return this// 自身のインスタンスを返す

    }

 

    public String 構築() {

        return 文字列ビルダー.toString();

    }

}

 

// 使用例

String 結果 = new ビルダー()

    .追加(“こんにちは”)

    .追加(“、”)

    .追加(“世界”)

    .構築();

内部クラスからの外部クラスの参照

内部クラス(ネストされたクラス)から外部クラスのインスタンスを参照する場合、「OuterClass.this」の形式を使用します。

public class 外部クラス {

    private String 名前 = “外部”;

 

    class 内部クラス {

        private String 名前 = “内部”;

 

        public void 表示() {

            System.out.println(this.名前);  // “内部”を表示

            System.out.println(外部クラス.this.名前);  // “外部”を表示

        }

    }

}

synchronizedブロックでの排他制御

thisを使用してsynchronizedブロックを作成すると、現在のオブジェクトを排他ロックとして使用できます。

public class 銀行口座 {

    private int 残高;

 

    public void 引き出し(int 金額) {    // 指定された金額を口座から引き出す処理をおこないます。

        synchronized(this) {    // 複数のスレッドが同時に 引き出し() メソッドにアクセスするのを防ぐ

            if (残高 >= 金額) {

                残高 -= 金額;

            }

        }

    }

}

上記例の「引き出し」メソッドでは、synchronizedキーワードにより、マルチスレッド環境での残高の不整合を防ぎます。

※より柔軟な同期処理が必要な場合は、java.util.concurrent.locksパッケージも使用できます。

メソッド引数としてのthisの使用

現在のオブジェクトを別のメソッドへ渡す際に、thisを使用できます。

public class イベント処理 {

    public void イベント登録() {

        イベントマネージャ.登録(this);  // 自分自身を引数として渡す

    }

 

    public void イベント発生() {

        // イベント処理のロジック

    }

}

 

public class イベントマネージャ {

    private static List<イベント処理> イベントリスナー = new ArrayList<>();

 

    public static void 登録(イベント処理 listener) {

        イベントリスナー.add(listener);

    }

 

    public static void イベント発生() {

        for (イベント処理 listener : イベントリスナー) {

            listener.イベント発生();

        }

    }

}

上記のコードでは、イベント登録でthisを登録することで、イベント発生時は個別のインスタンス毎のイベント発生メソッドを呼び出せます。

Javaのthisを使うときの注意点

Javaでthisキーワードは適切に使用すると、コードの可読性や保守性が向上しますが、誤った使い方をすると予期せぬ動作を引き起こす可能性があります。

コンストラクタでのthis()

this()は他のコンストラクタを呼び出すために使われますが、必ず最初の文として記述する必要があります。

public class 例クラス {

    private int 数値;

    private String 文字列;

 

    public 例クラス(int 数値) {

        this(数値, “デフォルト”);  // 正しい使用法

    }

 

    public 例クラス(int 数値, String 文字列) {

        this.数値 = 数値;

        this.文字列 = 文字列;

    }

}

thisの過剰使用

thisの過剰使用はコードを読みづらくします。

メンバ変数とローカル変数の名前が異なる場合、thisは不要です。以下に例を示します。

public class 従業員 {

    private String 名前;

 

    public void 名前設定(String 新しい名前) {

        名前 = 新しい名前;  // thisは不要

    }

}

継承時のthis

継承を使用した場合のオブジェクト指向特有の働きに注意してください。

public class 親クラス {

    protected String 名前 = “親”;

 

    public void 表示() {

        System.out.println(“親クラスの名前: “ + this.名前);  // “親”を表示

    }

}

 

public class 子クラス extends 親クラス {

    private String 名前 = “子”;

 

    @Override

    public void 表示() {

        System.out.println(“子クラスの名前: “ + this.名前);  // “子”を表示

        System.out.println(“親クラスの名前: “ + super.名前);  // “親”を表示

    }

}

 

親クラス 親 = new 親クラス();

子クラス 子 = new 子クラス();

親.表示();

子.表示();

上記のコードで、「this.名前」の対象が親クラスと子クラスで異なる点を理解しておくことは重要です。

まとめ

Javaのthisキーワードは、オブジェクト指向プログラミングの基本的な概念を支える重要な要素です。

変数の明確な区別、コンストラクタの効率的な呼び出し、メソッドチェーンの実現など、多岐にわたる使用方法があります。

thisの適切な使用法を理解したうえで、使いこなすと、より保守性の高い、読みやすいJavaコードを記述できます。

ぜひthisを活用してJavaプログラミングスキルを向上させてください。