Java入門|参照型の変数とメンバアクセス

悟空そのものではなく、悟空へのつながりを見る。参照型の変数とメンバアクセスをやさしく理解しよう

クラスからオブジェクトを作れるようになると、次に気になってくるのが「作ったオブジェクトをどうやって使うのか」という点です。サイヤ人クラスから悟空や悟飯のような実体を作れたとしても、それだけではまだ情報を入れたり取り出したりはできません。name や power や specialMove といった内容を設定して、はじめてそのオブジェクトらしさが見えてきます。

ここで大切になるのが、参照型の変数とメンバアクセスという考え方です。Javaでは、クラス型の変数はオブジェクトそのものを直接入れているわけではなく、オブジェクトがある場所をさし示す役目を持っています。そして、その変数を通してフィールドやメソッドにアクセスしていきます。

ドラゴンボールでたとえるなら、変数は悟空そのものではなく、「この先に悟空がいる」とわかる目印のようなものです。そして、その目印をたどることで、悟空の名前や戦闘力、技といった情報に触れられるようになります。ここでは、この感覚をしっかりつかみながら、参照型の変数とメンバアクセスをやさしく整理していきます。

変数はオブジェクトそのものではない

クラスからオブジェクトを作るとき、次のような形を書きました。

Saiyan goku = new Saiyan();

この1行を見ると、つい「goku という変数の中に、オブジェクトそのものが入っている」と考えたくなります。ですが、Javaのクラス型の変数は、そういう感覚とは少し違います。

クラス型の変数は、オブジェクトそのものを表しているのではなく、そのオブジェクトがある場所をさし示している変数です。
このような変数を、参照型の変数と呼びます。

つまり、goku という変数は「悟空そのもの」ではありません。
正確には、作られた Saiyan オブジェクトを参照するための変数です。

この考え方は最初は少し不思議に感じるかもしれませんが、ここを理解すると、あとで代入や値の設定の動きがとてもわかりやすくなります。

ドラゴンボールで考える参照型の感覚

ドラゴンボールの世界でイメージしてみましょう。

たとえば、管理画面に goku というラベルがあるとします。このラベルそのものが悟空ではありません。goku は、実際に存在している悟空という戦士につながる目印のようなものです。

つまり、

  • 実際の戦士 = オブジェクト
  • その戦士につながる目印 = 参照型の変数

という関係です。

このイメージで考えると、変数を見たときに
「これは戦士そのものではなく、その戦士を見つけるための手がかりなんだな」
と理解できます。

Javaの考え方ドラゴンボールでのたとえ
オブジェクト実際に存在する悟空
参照型の変数悟空につながる目印
参照するその目印をたどって悟空に触れる

クラス型の変数は参照型の変数

Javaにはいろいろな型がありますが、クラス型の変数は参照型の変数です。
つまり、Saiyan(サイヤ人) 型や Warrior(戦士) 型の変数は、オブジェクトそのものではなく、そのオブジェクトを参照するために使われます。

たとえば次のようなコードがあったとします。

Saiyan goku;
goku = new Saiyan();

このとき、

  • 1行目で Saiyan 型の変数 goku を用意する
  • 2行目で新しい Saiyan オブジェクトを作る
  • そのオブジェクトを、変数 goku が参照できるようにする

という流れになっています。

ここで大事なのは、変数 goku がオブジェクトに名前をつけているように見えても、実際にはそのオブジェクトをさすための変数だということです。

オブジェクトを作ると、フィールドに値を入れられるようになる

クラスを宣言しただけの段階では、name(名前) や power(戦闘力) や specialMove(技) といったフィールドの種類が決まっているだけでした。
そこにはまだ具体的な値は入っていません。

ですが、オブジェクトを作ると、今度はそのオブジェクトが持っているフィールドに実際の値を入れられるようになります。

たとえば Saiyan クラスに次のようなフィールドがあるとします。

class Saiyan
{
    String name;
    int power;
    String specialMove;
}

この設計図だけでは、まだ誰のことかは決まっていません。
ですが、オブジェクトを作れば、

  • name は 悟空
  • power は 9000
  • specialMove は かめはめ波

というように、具体的な内容を入れられるようになります。

この「オブジェクトが持っている情報に触れて値を入れること」が、次に出てくるメンバアクセスです。

メンバアクセスとは何か

クラスの中にあるフィールドやメソッドは、まとめてメンバと呼ばれます。
そして、そのメンバを使うことをメンバにアクセスするといいます。

フィールドに値を入れたり、値を取り出したり、メソッドを呼び出したりするときには、変数名のあとに . をつけて指定します。

たとえば、goku が参照している Saiyan オブジェクトの name フィールドを表したいなら、こう書きます。

goku.name

power ならこうです。

goku.power

specialMove ならこうです。

goku.specialMove

この . を使った書き方が、メンバアクセスの基本です。

ドラゴンボールでいうなら、goku という目印をたどって、その先にいるオブジェクトの「name」や「power」の欄を見に行く感覚です。

フィールドに値を代入する

では、実際にフィールドへ値を入れる流れを見てみましょう。

まずはオブジェクトを作ります。

Saiyan goku;
goku = new Saiyan();

次に、そのオブジェクトが持っているフィールドへ値を代入します。

goku.name = "悟空";
goku.power = 9000;
goku.specialMove = "かめはめ波";

これで、goku という変数が参照している Saiyan オブジェクトに、具体的な値が入ります。

指定入る値
goku.name悟空
goku.power9000
goku.specialMoveかめはめ波

ここでのポイントは、値を入れている相手が「変数そのもの」ではなく、変数が参照しているオブジェクトのフィールドだということです。

メンバアクセスは「どのオブジェクトの、どの情報か」を示す

メンバアクセスが大事なのは、どのオブジェクトの、どの情報なのかをはっきり指定できるからです。

たとえば、悟空とベジータの両方を作ったとします。

Saiyan goku = new Saiyan();
Saiyan vegeta = new Saiyan();

このあと、それぞれに値を入れるときは次のように書けます。

goku.name = "悟空";
goku.specialMove = "かめはめ波";

vegeta.name = "ベジータ";
vegeta.specialMove = "ファイナルフラッシュ";

このように書くことで、

  • 悟空の技はかめはめ波
  • ベジータの技はファイナルフラッシュ

というように、同じ Saiyan クラスから作られた別々のオブジェクトに、それぞれ異なる値を持たせられます。

もし . を使って区別しなければ、「誰の name なのか」「誰の specialMove なのか」がわからなくなってしまいます。
メンバアクセスは、その区別をきちんとつけるための書き方でもあります。

参照型の変数とメンバアクセスの関係

ここまでの内容をつなげると、次の流れになります。

  1. クラスからオブジェクトを作る
  2. 変数がそのオブジェクトを参照する
  3. 変数名.フィールド名 の形で、そのオブジェクトの情報にアクセスする
  4. そこに実際の値を入れる

この関係を表にすると、かなり整理しやすいです。

段階何をしているか
Saiyan goku;オブジェクトを参照するための変数を用意する
goku = new Saiyan();新しいオブジェクトを作り、goku がそれを参照する
goku.name = "悟空";参照しているオブジェクトの name フィールドに値を入れる
goku.power = 9000;参照しているオブジェクトの power フィールドに値を入れる

この流れが理解できると、メンバアクセスは単なる記号の使い方ではなく、参照先のオブジェクトに触れるための方法だと見えてきます。

プログラム全体で流れを見る

ここまでを、ドラゴンボールのたとえに合わせたプログラムで整理してみます。

class Saiyan
{
    String name;
    int power;
    String specialMove;
}

class Main
{
    public static void main(String[] args)
    {
        Saiyan goku;
        goku = new Saiyan();

        goku.name = "悟空";
        goku.power = 9000;
        goku.specialMove = "かめはめ波";

        System.out.println("名前は" + goku.name + "です。");
        System.out.println("戦闘力は" + goku.power + "です。");
        System.out.println("必殺技は" + goku.specialMove + "です。");
    }
}

このコードの流れはとても大切です。

まず Saiyan クラスがあり、name、power、specialMove というフィールドを持っています。
次に main メソッドの中で goku という変数を用意し、新しい Saiyan オブジェクトを作って参照させています。
そのあとで、goku.name、goku.power、goku.specialMove という形でメンバにアクセスし、実際の値を設定しています。

さらに最後には、設定した値を画面に表示しています。
ここでは、フィールド名は英語表記、表示メッセージは日本語という形でそろえています。

goku.name という書き方の意味を細かく見る

この書き方はとても重要なので、少し細かく見てみましょう。

goku.name

この式には2つの意味があります。

  • goku
    → Saiyan オブジェクトを参照している変数
  • name
    → そのオブジェクトが持っているフィールド

つまり、goku.name は
goku が参照しているオブジェクトの name フィールド
を表しています。

同じように、

goku.power

は、goku が参照しているオブジェクトの power フィールドです。

このように、. は「そのオブジェクトの中にあるメンバへ進む」ための道しるべのような役割をしています。

複数のオブジェクトがあるときこそ、参照型の意味が見えてくる

参照型の変数の感覚は、複数のオブジェクトがあるときによりはっきり見えてきます。

たとえば、悟空と悟飯を作るとします。

Saiyan goku = new Saiyan();
Saiyan gohan = new Saiyan();

goku.name = "悟空";
goku.specialMove = "かめはめ波";

gohan.name = "悟飯";
gohan.specialMove = "魔閃光";

このとき、goku と gohan は別々のオブジェクトを参照しています。
だから、同じ name フィールドや specialMove フィールドを持っていても、入る値は別々です。

変数参照しているオブジェクトの名前必殺技
goku悟空かめはめ波
gohan悟飯魔閃光

ここで、変数がオブジェクトそのものではなく、オブジェクトを参照するためのものだと考えると、とてもすっきり理解できます。
goku という変数は悟空オブジェクトにつながり、gohan という変数は悟飯オブジェクトにつながる。
そのため、それぞれ別々の情報を持たせられるのです。

この図では、左側の goku と gohan が参照型の変数です。
右側の大きな箱が、実際に作られた Saiyan オブジェクトです。

左から右へ伸びる矢印は、「この変数はこのオブジェクトを参照している」という意味です。
つまり、変数そのものがオブジェクトではなく、オブジェクトにつながっていることが視覚的にわかります。

さらに、goku.name という吹き出しをつけることで、メンバアクセスが「goku が参照しているオブジェクトの name 欄を見ること」だと理解しやすくなります。

メソッドもメンバアクセスで使う

ここでは中心がフィールドへのアクセスですが、メンバアクセスはフィールドだけに使うものではありません。
メソッドもメンバなので、同じように . を使って呼び出します。

たとえば、Saiyan クラスに showStatus というメソッドがあったとします。

class Saiyan
{
    String name;
    int power;
    String specialMove;

    void showStatus()
    {
        System.out.println("名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("必殺技は" + specialMove + "です。");
    }
}

このとき、goku が参照しているオブジェクトの showStatus メソッドを使うなら、こう書きます。

goku.showStatus();

つまりメンバアクセスは、

  • フィールドに値を入れる
  • フィールドの値を取り出す
  • メソッドを呼び出す

といった場面で使われます。

ここでは主にフィールドアクセスが中心ですが、. でオブジェクトの中のメンバに進むという感覚は共通です。

いちばん大事な感覚

参照型の変数とメンバアクセスで大事なのは、次の感覚です。

  • クラス型の変数はオブジェクトそのものではない
  • 変数はオブジェクトへのつながりを表している
  • そのつながりを使って、. でフィールドやメソッドにアクセスする
  • オブジェクトを作ると、具体的な値を入れられるようになる

ドラゴンボールで言いかえるなら、

  • goku という変数は悟空本人ではなく、悟空につながる目印
  • その目印をたどることで、悟空の name や power や specialMove に触れられる
  • goku.name や goku.specialMove という書き方は、その情報欄を直接指定している

ということです。

この感覚をつかめると、Javaのオブジェクト指向がぐっと立体的に見えてきます。
クラスから実体を作るだけで終わりではなく、その実体に対して情報を設定し、必要な機能を呼び出していく。その入口になるのが、参照型の変数とメンバアクセスです。