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

同じ設計図から生まれても、隊士ごとに中身は別々。
インスタンス変数とインスタンスメソッドを知ると、オブジェクトごとの情報と動きが見えてくる。

ここまでの学習で、クラスの中にはフィールド、メソッド、コンストラクタを書けることを学んできました。

クラスは、オブジェクトを作るための設計図です。
その設計図からオブジェクトを作ることで、実際に値を持たせたり、メソッドを呼び出したりできます。

鬼滅の刃でたとえると、DemonSlayer クラスは鬼殺隊士の設計図です。
その設計図から、水月や炎真のような個別の隊士オブジェクトを作れます。

ここで大切になるのが、「そのフィールドやメソッドは、どのオブジェクトに結びついているのか」という考え方です。

同じ DemonSlayer クラスから作られた隊士でも、水月の体力と炎真の体力は別々です。
水月に show() を呼び出せば水月の状態が表示され、炎真に show() を呼び出せば炎真の状態が表示されます。

このように、オブジェクトごとに結びついているフィールドをインスタンス変数といいます。
そして、オブジェクトごとに呼び出して使うメソッドをインスタンスメソッドといいます。

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

クラスの中には、フィールドやメソッドがあります。

フィールドは、オブジェクトが持つ情報です。
メソッドは、オブジェクトが行う処理です。

この2つをまとめてメンバと呼びます。

メンバ役割鬼滅の刃でたとえると
フィールド情報を持つ体力、呼吸の力
メソッド処理を行う状態設定、状態表示
メンバフィールドとメソッドの総称隊士の情報と技

たとえば DemonSlayer クラスには、次のようなフィールドとメソッドを用意できます。

種類役割
フィールドstamina体力を持つ
フィールドbreathingEnergy呼吸の力を持つ
メソッドsetDemonSlayer()体力と呼吸の力を設定する
メソッドshow()現在の状態を表示する

これらは、ただクラスに書かれているだけではありません。

DemonSlayer クラスから mizuki オブジェクトを作れば、mizuki の stamina と breathingEnergy ができます。
DemonSlayer クラスから enma オブジェクトを作れば、enma の stamina と breathingEnergy ができます。

つまり、同じクラスに書かれたフィールドでも、実際には各オブジェクトに結びついて使われます。

↓クリックすると拡大表示されます。

オブジェクトごとの値を確認する

実際のプログラムで確認してみましょう。

ファイル名:Sample7.java

class DemonSlayer
{
    private int stamina;
    private double breathingEnergy;

    public DemonSlayer()
    {
        stamina = 0;
        breathingEnergy = 0.0;
        System.out.println("隊士を作成しました。");
    }

    public void setDemonSlayer(int s, double e)
    {
        stamina = s;
        breathingEnergy = e;
        System.out.println("体力を" + stamina + " 呼吸の力を" + breathingEnergy + "にしました。");
    }

    public void show()
    {
        System.out.println("体力は" + stamina + "です。");
        System.out.println("呼吸の力は" + breathingEnergy + "です。");
    }
}

class Sample7
{
    public static void main(String[] args)
    {
        DemonSlayer mizuki = new DemonSlayer();
        mizuki.setDemonSlayer(100, 20.5);
        mizuki.show();

        DemonSlayer enma = new DemonSlayer();
        enma.setDemonSlayer(85, 30.5);
        enma.show();
    }
}

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

オブジェクト作り方
mizukinew DemonSlayer()
enmanew DemonSlayer()

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

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

main メソッドの前半では、mizuki に対して次の処理をしています。

DemonSlayer mizuki = new DemonSlayer();
mizuki.setDemonSlayer(100, 20.5);
mizuki.show();

この流れで、mizuki オブジェクトには次の値が設定されます。

フィールドmizuki の値
stamina100
breathingEnergy20.5

次に、enma に対して次の処理をしています。

DemonSlayer enma = new DemonSlayer();
enma.setDemonSlayer(85, 30.5);
enma.show();

この流れで、enma オブジェクトには次の値が設定されます。

フィールドenma の値
stamina85
breathingEnergy30.5

ここで大切なのは、mizuki と enma が同じ DemonSlayer クラスから作られていても、それぞれ別々の値を持っていることです。

オブジェクトstaminabreathingEnergy
mizuki10020.5
enma8530.5

鬼滅の刃でたとえると、同じ鬼殺隊士の設計図から水月と炎真が生まれても、水月の体力と炎真の体力は別々です。
水月の呼吸の力と炎真の呼吸の力も、それぞれ別々に存在します。

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

フィールドは、クラスの中に1回だけ書かれています。

private int stamina;
private double breathingEnergy;

しかし、実際にオブジェクトを作ると、そのフィールドはオブジェクトごとに値を持ちます。

つまり、次のように考えると分かりやすいです。

クラスに書かれているフィールド実際のイメージ
staminamizuki の stamina、enma の stamina
breathingEnergymizuki の breathingEnergy、enma の breathingEnergy

stamina という項目は DemonSlayer クラスに共通してあります。
しかし、mizuki の stamina と enma の stamina は別々です。

鬼滅の刃でたとえると、「体力」という項目は鬼殺隊士なら共通して持っています。
でも、水月の体力と炎真の体力は同じものではありません。

このように、フィールドが各オブジェクトに結びついていることを、フィールドがオブジェクトに関連づけられていると考えます。

インスタンス変数とは何か

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

今回の Sample7.java では、次の2つがインスタンス変数です。

インスタンス変数役割
stamina各隊士の体力を持つ
breathingEnergy各隊士の呼吸の力を持つ

これらは、オブジェクトを作ってはじめて具体的な値を持ちます。

DemonSlayer クラスの段階では、「体力を持てる」「呼吸の力を持てる」という設計があるだけです。
実際に mizuki や enma というオブジェクトを作ることで、それぞれに具体的な値が入ります。

オブジェクトstaminabreathingEnergy
mizuki10020.5
enma8530.5

インスタンス変数という言葉は少し長く感じるかもしれません。

でも、意味はシンプルです。

各インスタンス、つまり各オブジェクトにひもづく変数です。

鬼滅の刃でたとえると、それぞれの隊士が自分専用に持っている体力や呼吸の力です。

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

フィールドだけではありません。
メソッドも、オブジェクトに関連づけられて使われます。

たとえば、次のように書くと、mizuki に対して show() を呼び出します。

mizuki.show();

この場合、表示されるのは mizuki の stamina と breathingEnergy です。

一方で、次のように書くと、enma に対して show() を呼び出します。

enma.show();

この場合、表示されるのは enma の stamina と breathingEnergy です。

show() の定義は、DemonSlayer クラスの中に1つだけです。

public void show()
{
    System.out.println("体力は" + stamina + "です。");
    System.out.println("呼吸の力は" + breathingEnergy + "です。");
}

しかし、どのオブジェクトに対して呼び出すかによって、使われる値が変わります。

呼び出し表示される情報
mizuki.show()mizuki の stamina と breathingEnergy
enma.show()enma の stamina と breathingEnergy

鬼滅の刃でたとえると、水月に状態報告をさせれば水月の状態が報告されます。
炎真に状態報告をさせれば炎真の状態が報告されます。

同じ show() という技でも、誰に使わせるかによって見える状態が変わるのです。

インスタンスメソッドとは何か

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

今回の Sample7.java では、次の2つがインスタンスメソッドです。

インスタンスメソッド役割
setDemonSlayer(int s, double e)そのオブジェクトの体力と呼吸の力を設定する
show()そのオブジェクトの状態を表示する

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

mizuki.setDemonSlayer(100, 20.5);
mizuki.show();

enma.setDemonSlayer(85, 30.5);
enma.show();

ここで重要なのは、どのオブジェクトに対して呼び出しているかです。

mizuki.setDemonSlayer(100, 20.5) は、mizuki の値を設定します。
enma.setDemonSlayer(85, 30.5) は、enma の値を設定します。

同じ setDemonSlayer() でも、呼び出す相手によって、変更されるオブジェクトが違います。

鬼滅の刃でたとえると、同じ「隊士の状態を整える技」でも、水月に使えば水月の状態が整い、炎真に使えば炎真の状態が整うということです。

インスタンス変数とインスタンスメソッドはセットで考える

インスタンス変数とインスタンスメソッドは、別々に覚えるより、セットで考えると分かりやすいです。

どちらもオブジェクトに結びついているからです。

メンバオブジェクトに関連づくか種類
staminaはいインスタンス変数
breathingEnergyはいインスタンス変数
setDemonSlayer()はいインスタンスメソッド
show()はいインスタンスメソッド

鬼滅の刃でたとえると、こうなります。

Javaの用語鬼滅の刃でたとえると
インスタンス変数その隊士自身の体力や呼吸の力
インスタンスメソッドその隊士自身に使わせる技や報告

つまり、インスタンス変数は「そのオブジェクト自身の情報」です。
インスタンスメソッドは「そのオブジェクト自身の情報を使って動く処理」です。

この2つは、オブジェクトごとの状態と動きを表す大切なペアです。

実行結果からオブジェクトごとの違いを見る

Sample7.java を実行すると、次のような結果になります。

隊士を作成しました。
体力を100 呼吸の力を20.5にしました。
体力は100です。
呼吸の力は20.5です。

隊士を作成しました。
体力を85 呼吸の力を30.5にしました。
体力は85です。
呼吸の力は30.5です。

前半は、mizuki の情報です。

表示対象
体力を100 呼吸の力を20.5にしました。mizuki
体力は100です。mizuki
呼吸の力は20.5です。mizuki

後半は、enma の情報です。

表示対象
体力を85 呼吸の力を30.5にしました。enma
体力は85です。enma
呼吸の力は30.5です。enma

この結果を見ると、mizuki と enma の値が混ざっていないことが分かります。

mizuki には mizuki の stamina と breathingEnergy があります。
enma には enma の stamina と breathingEnergy があります。

同じ DemonSlayer クラスから作っても、オブジェクトごとに状態は別々です。

図:同じクラスから作っても値は別々

↓クリックすると拡大表示されます。

この図が示していること

この図では、DemonSlayer クラスという同じ設計図から、mizuki オブジェクトと enma オブジェクトが作られる流れを表しています。

どちらも同じ stamina と breathingEnergy というフィールドを持てます。
しかし、mizuki は stamina = 100、breathingEnergy = 20.5 を持ち、enma は stamina = 85、breathingEnergy = 30.5 を持っています。

ここから分かるのは、インスタンス変数はクラス全体で1つだけ共有されるのではなく、オブジェクトごとに別々の値を持つということです。

show() は呼び出した相手の状態を表示する

show() も、オブジェクトごとに働きます。

Sample7.java の show() は、次のように定義されています。

public void show()
{
    System.out.println("体力は" + stamina + "です。");
    System.out.println("呼吸の力は" + breathingEnergy + "です。");
}

この中では、stamina と breathingEnergy を表示しています。

ただし、どの stamina と breathingEnergy を使うかは、どのオブジェクトに対して show() を呼んだかで決まります。

mizuki.show();

なら、mizuki の stamina と breathingEnergy を表示します。

enma.show();

なら、enma の stamina と breathingEnergy を表示します。

呼び出し使われる値
mizuki.show()mizuki の stamina、mizuki の breathingEnergy
enma.show()enma の stamina、enma の breathingEnergy

鬼滅の刃でたとえると、水月に報告させれば水月の状態が分かります。
炎真に報告させれば炎真の状態が分かります。

同じ報告の技でも、誰が使うかで中身が変わります。

図:インスタンスメソッドは呼び出した相手に働く

↓クリックすると拡大表示されます。

この図が示していること

この図では、同じ show() メソッドでも、呼び出した相手によって表示される情報が変わることを示しています。

mizuki.show() では、mizuki オブジェクトの stamina と breathingEnergy が使われます。
そのため、体力は100、呼吸の力は20.5と表示されます。

一方で、enma.show() では、enma オブジェクトの stamina と breathingEnergy が使われます。
そのため、体力は85、呼吸の力は30.5と表示されます。

ここから分かるのは、インスタンスメソッドは、呼び出したオブジェクト自身の状態を使って働くということです。

各オブジェクトごとに持つという感覚が大切

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

DemonSlayer クラスという設計図は1つです。

しかし、その設計図から作られるオブジェクトは1つとは限りません。

mizuki も作れます。
enma も作れます。

そのとき、体力や呼吸の力は共通の1つを使い回しているわけではありません。

項目考え方
stamina各オブジェクトごとに別々
breathingEnergy各オブジェクトごとに別々
setDemonSlayer()呼び出したオブジェクトに対して働く
show()呼び出したオブジェクトの状態を表示する

鬼滅の刃でたとえると、鬼殺隊士という設計図は共通です。

しかし、水月には水月の体力があります。
炎真には炎真の体力があります。
水月に状態設定をすれば水月の状態が変わります。
炎真に状態設定をすれば炎真の状態が変わります。

この「オブジェクトごと」という感覚が、インスタンスを理解する中心です。

いちばん大事な感覚

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

ポイント内容
インスタンス変数オブジェクトごとに別々の値を持つフィールド
インスタンスメソッドオブジェクトごとに呼び出して使うメソッド
同じクラスから作ってもオブジェクトごとに中身は別々
show() の動き呼び出したオブジェクト自身の値を表示する
setDemonSlayer() の動き呼び出したオブジェクト自身の値を変更する

鬼滅の刃でたとえると、同じ鬼殺隊士の設計図から生まれても、水月と炎真は別々の隊士です。

水月の体力と炎真の体力は別々。
水月の呼吸の力と炎真の呼吸の力も別々。
水月に show() を使えば水月の状態が見え、炎真に show() を使えば炎真の状態が見えます。

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