thisキーワード:自分のオブジェクトを指し示す

docs

以前の記事では、クラスとインスタンスの関係について学んだよね。クラスは「設計図」、インスタンスは「設計図から作られた実際のモノ」だった。

クラスとオブジェクトの概念 – オブジェクト指向の入り口 | ToolDocs

今回は、そのインスタンス自身を指し示す特別なキーワード、thisについて掘り下げていこう。


thisってなんだ?

Javaを書いていると、クラスの中で「このインスタンス自身のデータ」や「このインスタンス自身のメソッド」を使いたい場面がよく出てくる。そんなときに活躍するのがthisキーワードだ。thisは、現在操作しているインスタンスそのものを指すんだ。

例えば、君が「タマ」という名前の犬のインスタンスを操作しているとする。そのとき「タマ自身の名前」とか「タマ自身が吠える」といったことを表現したいよね。thisはまさに、その「タマ自身」を指し示す役割を果たすんだ。


thisの具体的な使い方

thisの主な使い方は、次の3つ。

  1. インスタンス変数とローカル変数の区別
  2. コンストラクタからの別のコンストラクタの呼び出し
  3. 現在のインスタンスをメソッドに渡す

それぞれ詳しく見ていこう。

1. インスタンス変数とローカル変数の区別

これがthisの一番よく使う場面かもしれない。

例えば、Dogクラスにnameというインスタンス変数があるとする。そして、そのnameを設定するsetNameメソッドの引数もたまたまnameという名前にしたとしよう。

Java

class Dog {
    String name; // インスタンス変数

    void setName(String name) { // 引数もname
        name = name; // これだとどうなると思う?
    }
}

このsetNameメソッドの中のname = name;は、どちらのnameを指しているか分かるかな? 実はこれ、両方ともメソッドの引数であるローカル変数のnameを指してしまうんだ。だから、インスタンス変数のnameには何も設定されない!

そこで登場するのがthisだ。

Java

class Dog {
    String name; // インスタンス変数

    void setName(String name) { // 引数もname
        this.name = name; // this.name はインスタンス変数、name は引数
    }

    String getName() {
        return this.name; // this.name はインスタンス変数
    }
}

public class ThisExample {
    public static void main(String[] args) {
        Dog pochi = new Dog();
        pochi.setName("ポチ");
        System.out.println("犬の名前:" + pochi.getName()); // 出力: 犬の名前:ポチ

        Dog hana = new Dog();
        hana.setName("ハナ");
        System.out.println("犬の名前:" + hana.getName()); // 出力: 犬の名前:ハナ
    }
}

this.nameと書くことで、「これはこのDogインスタンスが持っているname変数だよ」と明確に指定できるんだ。これによって、引数のnameの値が、インスタンス変数のnameに正しく代入されるようになる。

getName()メソッドの中でもthis.nameと書いたけど、ここではローカル変数や引数にnameという名前のものが他にないから、thisをつけなくてもインスタンス変数を指してくれる。でも、つけておくことで「これはインスタンス変数だぞ」ということを明示できるから、読みやすさが上がることもあるよ。

paizaで実行した結果


2. コンストラクタからの別のコンストラクタの呼び出し

クラスには、インスタンスを作るための特別なメソッドであるコンストラクタがあるって話はしたかな?(もし忘れていたら、ぜひ前回の記事も見てみてね! Javaのクラスとインスタンス

thisは、あるコンストラクタの中から同じクラスの別のコンストラクタを呼び出すときにも使えるんだ。これは、コンストラクタの処理を共通化したい場合に便利だよ。

例えば、Carクラスにコンストラクタがいくつかあるとしよう。

Java

class Car {
    String model;
    String color;
    int year;

    // 引数なしのコンストラクタ
    Car() {
        this("不明なモデル", "白", 2024); // このクラスの別のコンストラクタを呼び出す
        System.out.println("引数なしコンストラクタが呼ばれました。");
    }

    // モデルと色の引数があるコンストラクタ
    Car(String model, String color) {
        this(model, color, 2025); // このクラスの別のコンストラクタを呼び出す
        System.out.println("モデルと色のコンストラクタが呼ばれました。");
    }

    // 全ての引数があるコンストラクタ
    Car(String model, String color, int year) {
        this.model = model;
        this.color = color;
        this.year = year;
        System.out.println("全ての引数があるコンストラクタが呼ばれました。");
    }

    void displayCarInfo() {
        System.out.println("モデル: " + model + ", 色: " + color + ", 年式: " + year);
    }
}

public class ThisConstructorExample {
    public static void main(String[] args) {
        System.out.println("--- car1 ---");
        Car car1 = new Car(); // 引数なしコンストラクタを呼び出す
        car1.displayCarInfo();
        // 出力:
        // 全ての引数があるコンストラクタが呼ばれました。
        // 引数なしコンストラクタが呼ばれました。
        // モデル: 不明なモデル, 色: 白, 年式: 2024

        System.out.println("\n--- car2 ---");
        Car car2 = new Car("プリウス", "黒"); // モデルと色のコンストラクタを呼び出す
        car2.displayCarInfo();
        // 出力:
        // 全ての引数があるコンストラクタが呼ばれました。
        // モデルと色のコンストラクタが呼ばれました。
        // モデル: プリウス, 色: 黒, 年式: 2025

        System.out.println("\n--- car3 ---");
        Car car3 = new Car("ノート", "赤", 2023); // 全ての引数があるコンストラクタを直接呼び出す
        car3.displayCarInfo();
        // 出力:
        // 全ての引数があるコンストラクタが呼ばれました。
        // モデル: ノート, 色: 赤, 年式: 2023
    }
}

この例では、引数なしコンストラクタとモデルと色のコンストラクタから、this(...)を使って全ての引数があるコンストラクタを呼び出しているのが分かるかな? これによって、初期化のロジックを1箇所にまとめられるから、コードがすっきりして保守もしやすくなるんだ。

paizaで実行した結果


3. 現在のインスタンスをメソッドに渡す

これは少し上級者向けかもしれないけど、知っておくと役立つ場面があるよ。 あるメソッドの中で、「このインスタンス自身を、別のメソッドの引数として渡したい」という場合があるんだ。例えば、複数のオブジェクトが連携して動作するようなデザインパターン(Javaのデザインパターンは将来学ぶ機会があるかも!)などで使われることがある。

Java

class ReportGenerator {
    void generateReport(Student student) {
        System.out.println("レポート作成中...");
        System.out.println("生徒名: " + student.getName());
        System.out.println("学籍番号: " + student.getStudentId());
        System.out.println("--------------------");
    }
}

class Student {
    String name;
    String studentId;

    Student(String name, String studentId) {
        this.name = name;
        this.studentId = studentId;
    }

    String getName() {
        return name;
    }

    String getStudentId() {
        return studentId;
    }

    // 自分自身を引数として渡すメソッド
    void requestReport() {
        ReportGenerator generator = new ReportGenerator();
        generator.generateReport(this); // ここで自分自身(このStudentインスタンス)を渡している
    }
}

public class ThisAsArgumentExample {
    public static void main(String[] args) {
        Student taro = new Student("山田太郎", "S001");
        taro.requestReport(); // 山田太郎のレポートを作成する
        // 出力:
        // レポート作成中...
        // 生徒名: 山田太郎
        // 学籍番号: S001
        // --------------------

        Student hanako = new Student("佐藤花子", "S002");
        hanako.requestReport(); // 佐藤花子のレポートを作成する
        // 出力:
        // レポート作成中...
        // 生徒名: 佐藤花子
        // 学籍番号: S002
        // --------------------
    }
}

この例では、StudentクラスのrequestReportメソッドの中で、thisを使って**自分自身(そのStudentインスタンス)**をReportGeneratorクラスのgenerateReportメソッドに渡しているのが分かるかな? これによって、ReportGeneratorは渡されたStudentインスタンスの情報を元にレポートを作成できるんだ。

paizaで実行した結果


まとめ

thisキーワードは、Javaプログラミングにおいて現在のインスタンス自身を指し示す、とても重要な役割を持っている。

  • インスタンス変数とローカル変数の名前が同じ場合に区別するため (this.変数名)
  • コンストラクタから同じクラスの別のコンストラクタを呼び出すため (this(...))
  • 現在のインスタンスを別のメソッドに引数として渡すため (メソッド名(this))

これらの使い方をマスターすることで、より柔軟で理解しやすいコードが書けるようになるはずだ。


Javaの学習は一歩ずつ着実に進めていくことが大切だね。もし分からなくなったら、いつでも前の記事に戻って復習してみてくれ。

次の記事もお楽しみに!

クラスとオブジェクトの概念 – オブジェクト指向の入り口 | ToolDocs

コメント

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