Java入門|クラス型変数と参照のしくみ

クラス型変数の正体を見抜け!悟空とベジータで理解する「参照」のしくみ

これまでクラスからオブジェクトを作成し、それを変数で扱う方法を学んできました。
ここからは一歩進んで、「クラス型の変数とは本当は何を持っているのか?」という本質に迫っていきます。

ドラゴンボールの世界で考えてみましょう。
悟空やベジータは「戦士(Saiyan)」という種族の設計図(クラス)から生まれた存在です。そして、プログラム上の変数は、そのキャラクターそのものではなく、「そのキャラクターを指している存在」なのです。

この考え方が理解できると、オブジェクト指向の理解が一気に深まります。

クラス型変数は「戦士そのもの」ではない

まず重要なポイントです。

クラス型の変数は、オブジェクトそのものではありません。
「どのオブジェクトを指しているか」という情報を持っています。

ドラゴンボールでたとえるとこうなります。

概念ドラゴンボールでの例
クラスサイヤ人という種族
オブジェクト悟空、ベジータ
変数キャラクターを指し示すタグ

つまり、変数は「悟空そのもの」ではなく、「悟空を指している札」のようなものです。

同じオブジェクトを複数の変数で扱う

次のサンプルを見てみましょう。

ファイル名:Sample6.java

class Saiyan
{
    private int power;
    private double energy;

    public Saiyan()
    {
        power = 0;
        energy = 0.0;
        System.out.println("戦士を生成しました。");
    }

    public void setSaiyan(int p, double e)
    {
        power = p;
        energy = e;
        System.out.println("戦闘力を" + power + "、気力を" + energy + "に設定しました。");
    }

    public void show()
    {
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("気力は" + energy + "です。");
    }
}

class Sample6
{
    public static void main(String[] args)
    {
        Saiyan goku;
        System.out.println("gokuを宣言しました。");

        goku = new Saiyan();
        goku.setSaiyan(9000, 5000.0);

        Saiyan vegeta;
        System.out.println("vegetaを宣言しました。");

        vegeta = goku;
        System.out.println("vegetaにgokuを代入しました。");

        System.out.print("gokuがさす");
        goku.show();

        System.out.print("vegetaがさす");
        vegeta.show();
    }
}

ここで起きていることはとても重要です。

  • goku → 悟空を指す
  • vegeta → gokuを代入したので同じ悟空を指す

つまり、

悟空が2人いるのではなく
2つの変数が同じ悟空を指している

という状態になります。

この図では、「変数は実体ではなく参照」ということを表現しています。

片方を変更すると両方に影響する

次のコードを見てみましょう。

ファイル名:Sample7.java

class Sample7
{
    public static void main(String[] args)
    {
        Saiyan goku = new Saiyan();
        goku.setSaiyan(9000, 5000.0);

        Saiyan vegeta = goku;

        System.out.println("悟空の状態を変更します。");

        goku.setSaiyan(12000, 8000.0);

        System.out.print("gokuがさす");
        goku.show();

        System.out.print("vegetaがさす");
        vegeta.show();
    }
}

実行するとこうなります。

  • gokuを変更したのに
  • vegetaの結果も変わる

なぜか?

答えはシンプルです。

両方とも同じ悟空を指しているから

nullのしくみ(参照を切る)

次に重要なのが null です。

Saiyan goku = new Saiyan();
goku = null;

これはどういう意味かというと

gokuは誰も指していない状態になる

ドラゴンボールでたとえると

「悟空へのリンクが切れた状態」

です。

ガーベッジコレクションの考え方

もしどの変数からも参照されなくなったオブジェクトは、

Javaが自動的に削除します

これをガーベッジコレクションといいます。

ドラゴンボールでいうと、

誰にも認識されなくなったキャラクターが消える

ようなイメージです。

重要ポイント整理

  • クラス型の変数はオブジェクトそのものではない
  • 変数は「オブジェクトを指す参照」を持つ
  • 複数の変数が同じオブジェクトを指すことがある
  • どちらから変更しても同じオブジェクトに影響する
  • nullは参照を切る
  • 参照されなくなったオブジェクトは自動的に回収される

この「参照」という考え方は、Javaの中でも特に重要な概念です。
ここをしっかり理解できると、次の「配列」「コレクション」「オブジェクトのコピー」などの理解が一気に楽になります。