Java入門|インスタンス変数とインスタンスメソッド

悟空とベジータは同じ設計図から生まれても中身は別々。インスタンスごとの情報と動きをつかもう

ここまでの学習で、クラスの中にはフィールド、メソッド、コンストラクタを書けることを学んできました。クラスは戦士の設計図であり、そこからオブジェクトを作ることで、実際に値を持ったり、メソッドを呼び出したりできることも見えてきましたね。ここまで理解できると、次に整理したくなるのが「そのフィールドやメソッドは、誰にひもづいているのか」という点です。

ドラゴンボールで考えるとわかりやすいです。サイヤ人クラスという同じ設計図から悟空とベジータを作ったとしても、悟空の戦闘力とベジータの戦闘力は別々ですし、show() を呼び出したときも、それぞれ自分自身の情報を表示します。つまり、同じクラスの中に書かれたフィールドやメソッドでも、各オブジェクトに結びついて働くものがあるわけです。これがインスタンス変数とインスタンスメソッドです。ここでは、その考え方をドラゴンボールのたとえでやさしく整理していきます。

クラスの中のメンバは、オブジェクトと結びついて使われることがある

これまで学んできたクラスの中には、たとえば次のようなものがありました。

  • フィールド
  • メソッド
  • コンストラクタ

このうち、フィールドとメソッドはメンバです。
そして、この節で特に注目するのは、オブジェクトごとに持たれるフィールドや、オブジェクトごとに呼び出されるメソッドです。

たとえば Saiyan クラスを考えると、

  • power
  • energy

のようなフィールドがあり、

  • setSaiyan()
  • show()

のようなメソッドがありました。

これらは、ただクラスに書いてあるだけではなく、実際には作られた各オブジェクトと結びついて使われます。
だから悟空の power とベジータの power は別々に持てるし、悟空の show() とベジータの show() も、それぞれ自分自身の情報を表示するわけです。

実際のプログラムで見てみる

まずは、サンプルプログラムをドラゴンボールの世界に置きかえて見てみましょう。

ファイル名:Sample7.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 Sample7
{
    public static void main(String[] args)
    {
        Saiyan goku = new Saiyan();
        goku.setSaiyan(9000, 20.5);
        goku.show();

        Saiyan vegeta = new Saiyan();
        vegeta.setSaiyan(8500, 30.5);
        vegeta.show();
    }
}

このプログラムでは、Saiyan クラスから2つのオブジェクトを作っています。

  • goku
  • vegeta

どちらも同じ Saiyan クラスから作られています。
でも、設定される値は別々です。

オブジェクトごとに別々の値を持てる

main メソッドの前半では、goku に対してこうしています。

Saiyan goku = new Saiyan();
goku.setSaiyan(9000, 20.5);
goku.show();

これによって goku は、

  • power = 9000
  • energy = 20.5

という状態になります。

次に、vegeta に対してはこうしています。

Saiyan vegeta = new Saiyan();
vegeta.setSaiyan(8500, 30.5);
vegeta.show();

こちらでは、

  • power = 8500
  • energy = 30.5

という状態になります。

ここでとても大切なのは、同じ Saiyan クラスの中にある power と energy を使っていても、goku の値と vegeta の値は混ざらないということです。

表で整理するとこうなります。

オブジェクトpowerenergy
goku900020.5
vegeta850030.5

このように、フィールドの値は各オブジェクトごとに別々に存在しています。

フィールドがオブジェクトに関連づけられているという意味

このような動きを見て、「フィールドはオブジェクトに関連づけられている」と言います。

少しかたい表現ですが、意味はシンプルです。

たとえば power というフィールドは、クラスに1回だけ書いてあります。
でも実際には、

  • goku の power
  • vegeta の power

のように、各オブジェクトごとにそれぞれの値を持ちます。

つまり power は、ただクラスの中にあるだけではなく、作られたそれぞれのオブジェクトの中に1つずつ存在すると考えるとわかりやすいです。

ドラゴンボールで言えば、「戦闘力」という項目はサイヤ人クラスに共通してあるけれど、悟空の戦闘力とベジータの戦闘力は別物です。まさにその感覚です。

こうしたフィールドをインスタンス変数という

各オブジェクトに関連づけられているフィールドのことを、インスタンス変数といいます。

今回のサンプルなら、

  • power
  • energy

がインスタンス変数です。

なぜなら、これらはオブジェクトを作ってはじめて具体的な値を持ち、しかもその値はオブジェクトごとに別々だからです。

表でまとめるとこうです。

フィールド役割種類
power戦闘力を持つインスタンス変数
energy気の量を持つインスタンス変数

インスタンス変数という言葉が少し長く感じるかもしれませんが、
各インスタンス、つまり各オブジェクトにひもづく変数
と考えれば大丈夫です。

メソッドもオブジェクトに関連づけられている

フィールドだけではありません。
show() や setSaiyan() のようなメソッドも、今回のサンプルではオブジェクトごとに使われています。

たとえば、

goku.show();

と書けば、goku の power と energy を表示します。

一方で、

vegeta.show();

と書けば、vegeta の power と energy を表示します。

show() というメソッドの定義はクラスの中に1つしかありません。
でも、どのオブジェクトに対して呼ぶかによって、使われるデータは変わります。

つまり show() も、オブジェクトと関連づけられているわけです。

こうしたメソッドをインスタンスメソッドという

各オブジェクトに関連づけられているメソッドのことを、インスタンスメソッドといいます。

今回のサンプルでは、

  • setSaiyan()
  • show()

がインスタンスメソッドです。

なぜなら、これらはオブジェクトを作ってから、そのオブジェクトに対して呼び出しているからです。

たとえば show() を呼び出すとき、

  • goku.show()
  • vegeta.show()

のように、どのオブジェクトの show() かを指定しています。

そしてその結果、表示される内容もオブジェクトごとに違います。

つまりインスタンスメソッドは、
そのオブジェクト自身の状態を使って働くメソッド
だと考えるとわかりやすいです。

インスタンス変数とインスタンスメソッドはセットで考えるとわかりやすい

ここまでを整理すると、今回の Saiyan クラスでは次のようになります。

メンバインスタンスに関連づけられているか種類
powerはいインスタンス変数
energyはいインスタンス変数
setSaiyan()はいインスタンスメソッド
show()はいインスタンスメソッド

ここで大事なのは、インスタンス変数とインスタンスメソッドを別々に覚えるよりも、
どちらもオブジェクトと結びついている
という共通点で見ることです。

ドラゴンボールで言えば、

  • 戦闘力や気の量は、その戦士自身の情報
  • show() や setSaiyan() は、その戦士自身に対して使う技

という関係です。

だから、インスタンス変数とインスタンスメソッドはセットで理解するとすっきりします。

実行結果からも「オブジェクトごと」が見えてくる

この Sample7.java を実行すると、次のような流れになります。

戦士を作成しました。
戦闘力を9000 気の量を20.5にしました。
戦闘力は9000です。
気の量は20.5です。

戦士を作成しました。
戦闘力を8500 気の量を30.5にしました。
戦闘力は8500です。
気の量は30.5です。

この結果をよく見ると、goku と vegeta の情報がちゃんと分かれていることがわかります。

もしフィールドがオブジェクトごとに分かれていなければ、2回目の設定で1回目の情報までおかしくなってしまいそうです。
でも実際にはそうなっていません。

これは、

  • goku には goku の power と energy がある
  • vegeta には vegeta の power と energy がある

からです。

つまり実行結果そのものが、インスタンス変数の考え方をはっきり示してくれています。

「各オブジェクトごとに持つ」という感覚が重要

インスタンス変数とインスタンスメソッドを理解するときに、いちばん大事なのは
各オブジェクトごとに持つ
という感覚です。

たとえば Saiyan クラスという設計図があっても、そこから作られた戦士は1人ではありません。
悟空もベジータも作れます。

そのとき、

  • 戦闘力は共通ではなく、それぞれの戦士ごとにある
  • 気の量も共通ではなく、それぞれの戦士ごとにある
  • show() も「どの戦士に対して呼んだか」で働き方が変わる

ということです。

この「ごとに」という感覚がつかめると、インスタンスという言葉の意味もかなり見えてきます。

図で見るとさらにわかりやすい

この図では、左側に Saiyan クラスがあり、その中に power、energy、setSaiyan()、show() が書かれています。
これによって、設計図の中に情報と機能があることが見えます。

右側には goku オブジェクトと vegeta オブジェクトがあり、それぞれ別の値を持っています。
ここを見ると、power や energy はクラスに1回書いてあっても、実際にはオブジェクトごとに別々の値を持つことがわかります。

また、setSaiyan() や show() から各オブジェクトへ矢印が伸びていることで、メソッドもオブジェクトごとに使われていることが見やすくなります。

いちばん大事な感覚

「インスタンス変数とインスタンスメソッド」で大切なのは、次の感覚です。

  • オブジェクトごとに別々の値を持つフィールドがある
  • オブジェクトごとに呼び出して使うメソッドがある
  • そうしたフィールドをインスタンス変数という
  • そうしたメソッドをインスタンスメソッドという
  • 同じクラスから作られたオブジェクトでも、中身はそれぞれ別々に存在する

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

  • 悟空の戦闘力とベジータの戦闘力は別々
  • 悟空に show() を使えば悟空の状態が見え、ベジータに show() を使えばベジータの状態が見える
  • だから、それぞれの戦士にひもづいた情報や技として考えるとわかりやすい

ということです。

この感覚がつかめると、クラスとオブジェクトの関係がさらに立体的に見えてきます。インスタンス変数とインスタンスメソッドは、まさに「各オブジェクト自身の情報と動き」を表す、とても大切な考え方です。