Java超|クラスとメソッドのしくみ

メソッドは、クラスに宿る必殺技。フィールドで戦士の情報を持ち、メソッドを呼び出すことで、悟空オブジェクトは本当に動き出します。

ここまでで、クラスにはフィールドを用意できること、そしてクラスからオブジェクトを作り、そのフィールドに具体的な値を入れられることを確認してきました。

ただ、オブジェクト指向のおもしろさは、情報を持たせることだけではありません。

クラスには、情報だけでなく「動き」もまとめられます。
Javaでは、この動きをメソッドで表します。

ドラゴンボールの世界観でたとえるなら、サイヤ人戦士が持っている名前、戦闘力、流派の印、流派名はフィールドです。
一方で、自分の情報を表示する、戦闘前に名乗る、必殺技を発動する、といった行動がメソッドです。

つまり、メソッドはクラスの中に定義する機能であり、戦士にとっての必殺技や行動パターンのようなものです。

フィールドだけを持つクラスは、戦士のプロフィールカードのようなものです。
そこにメソッドが加わると、その戦士は自分の状態を伝えたり、行動したりできるようになります。

この記事では、メソッドをどう定義するのか、どう呼び出すのか、そしてクラスの外側と内側でメンバへのアクセス方法がどう変わるのかを、ドラゴンボールの世界観で整理していきます。

メソッドはクラスの中の機能をまとめるしくみ

クラスには、情報を表すフィールドだけでなく、機能を表すメソッドも入れられます。

たとえば、サイヤ人を表す Saiyan クラスを考えてみます。

フィールドには、次のような情報を入れられます。

種類内容
フィールドname、power、styleMark、styleName

これは、戦士の状態を表す情報です。

フィールド意味例
name戦士の名前悟空
power戦闘力9000
styleMark流派の印亀
styleName流派名亀仙流

一方で、戦士には情報だけでなく、できる動きもあります。

種類内容
メソッドshow、showSaiyan など
メソッド役割
show戦士の情報を表示する
showSaiyan案内文を出してから戦士情報を表示する

ドラゴンボールで言えば、戦士には「名前がある」「戦闘力がある」「流派に属している」という状態だけでなく、「自分の情報を表示する」「戦闘前に名乗る」といった行動もあります。

この行動をまとめる場所がメソッドです。

クラスは、次の2つを合わせ持つことができます。

要素役割ドラゴンボールでのイメージ
フィールド情報を持つ戦士のプロフィール
メソッド動きを持つ戦士の行動や必殺技

この2つがそろうことで、クラスはただのデータの箱ではなく、役割を持った部品として使えるようになります。

図:フィールドとメソッドを持つクラス

この図が示していること

この図は、クラスの中にフィールドとメソッドの両方を入れられることを示しています。

フィールドは、name、power、styleMark、styleName のように、オブジェクトが持つ情報です。
メソッドは、show() や showSaiyan() のように、オブジェクトが実行できる処理です。

この図から分かることは、クラスは単なる情報の置き場ではなく、情報と動きをまとめた部品だということです。

メソッドを定義するとは何か

メソッドは、まとまった処理をひとつの名前でくくるためのしくみです。

たとえば、「戦士の情報を表示する」という処理を毎回長く書くのは大変です。

System.out.println("戦士の名前は" + name + "です。");
System.out.println("戦闘力は" + power + "です。");
System.out.println("流派の印は「" + styleMark + "」です。");
System.out.println("流派名は" + styleName + "です。");

このような表示処理を show というメソッドにまとめておけば、必要なときに show を呼び出すだけで、同じ処理を実行できます。

void show()
{
    System.out.println("戦士の名前は" + name + "です。");
    System.out.println("戦闘力は" + power + "です。");
    System.out.println("流派の印は「" + styleMark + "」です。");
    System.out.println("流派名は" + styleName + "です。");
}

この show メソッドには、4つの表示処理がまとまっています。

ドラゴンボールでたとえるなら、これは「自分の戦士情報を名乗る技」をひとつにまとめたようなものです。

メソッドでまず押さえたいことは、次の3つです。

ポイント内容
名前を持つshow のように処理のまとまりに名前を付ける
処理をまとめられる複数の文をひとまとめにできる
呼び出して使う定義しただけでは動かず、呼び出すと実行される

メソッドを使うと、同じ処理を何度も書かずに済みます。
また、処理の意味が名前で分かるため、コードも読みやすくなります。

フィールドとメソッドはどちらもメンバ

クラスの中にあるフィールドとメソッドは、まとめてメンバと呼ばれます。

メンバの種類役割
フィールド情報を持つ
メソッド処理を持つ

たとえば Saiyan クラスなら、次のように考えられます。

メンバ種類
nameフィールド
powerフィールド
styleMarkフィールド
styleNameフィールド
showメソッド
showSaiyanメソッド

フィールドは状態を表します。
メソッドは動きを表します。

ドラゴンボールで言えば、フィールドは悟空のプロフィール、メソッドは悟空が使える行動や必殺技です。

この違いを意識しておくと、クラスの中に書かれている内容がかなり読みやすくなります。

情報を表示するメソッドを作る

まずは、戦士の情報を表示するメソッドを考えてみます。

Saiyan クラスに name、power、styleMark、styleName というフィールドを用意し、それを表示する show メソッドを作ります。

class Saiyan
{
    String name;
    int power;
    String styleMark;
    String styleName;

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("流派の印は「" + styleMark + "」です。");
        System.out.println("流派名は" + styleName + "です。");
    }
}

このクラスの中には、次のメンバがあります。

メンバ種類内容
nameフィールド戦士の名前
powerフィールド戦闘力
styleMarkフィールド流派の印
styleNameフィールド流派名
showメソッド戦士の情報を表示する

show メソッドの中では、name、power、styleMark、styleName を使ってメッセージを表示しています。

ここがとても大切です。

メソッドは、同じクラスの中にあるフィールドを使って処理を行えます。

ドラゴンボールで言えば、悟空が自分自身の名前、戦闘力、流派の印、流派名を使って、戦闘前に名乗っているようなイメージです。

流派情報をフィールドとして持たせる

この記事では、流派を表す情報として styleMark と styleName を使います。

styleMark は、流派を短く表す印です。
styleName は、流派の正式な名前です。

styleMarkstyleName
亀亀仙流
鶴鶴仙流
武武泰斗流
塔カリン流
魔ピッコロ魔族流
神神流(ナメック流)
惑惑星戦士流
界北の界王流

今回の Sample2.java と Sample3.java では、悟空の流派を次のように扱います。

フィールド値
styleMark亀
styleName亀仙流

styleMark は道着やカードに表示する短い印、styleName は正式な流派名として使います。

メソッドを呼び出すと定義した処理が実行される

メソッドは、定義しただけではまだ動きません。

実際にその処理を行うには、メソッドを呼び出す必要があります。

オブジェクトのメソッドを呼び出すときは、オブジェクトを参照する変数名に . をつけて、メソッド名と () を書きます。

たとえば、goku が Saiyan オブジェクトを参照しているなら、次のように書きます。

goku.show();

これで、goku が参照しているオブジェクトの show メソッドを実行できます。

フィールドアクセスと比べると、形がよく似ています。

書き方意味
goku.namegoku が参照するオブジェクトの name フィールドにアクセスする
goku.show()goku が参照するオブジェクトの show メソッドを呼び出す

ドラゴンボールで言えば、goku という目印をたどって、その先にいる悟空に「自分の情報を表示して」と命じている感じです。

実際のプログラムで流れを確認する

ここでは、メソッドを定義して、それを2回呼び出すプログラムを見ていきます。

ファイル名:Sample2.java

class Saiyan
{
    String name;
    int power;
    String styleMark;
    String styleName;

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("流派の印は「" + styleMark + "」です。");
        System.out.println("流派名は" + styleName + "です。");
    }
}

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

        goku.name = "悟空";
        goku.power = 9000;
        goku.styleMark = "亀";
        goku.styleName = "亀仙流";

        goku.show();
        goku.show();
    }
}

このプログラムでは、まず Saiyan クラスの中で show メソッドを定義しています。

void show()
{
    System.out.println("戦士の名前は" + name + "です。");
    System.out.println("戦闘力は" + power + "です。");
    System.out.println("流派の印は「" + styleMark + "」です。");
    System.out.println("流派名は" + styleName + "です。");
}

そのあと main メソッドの中で、goku という変数を用意し、新しい Saiyan オブジェクトを作っています。

Saiyan goku;
goku = new Saiyan();

次に、name、power、styleMark、styleName に値を入れています。

goku.name = "悟空";
goku.power = 9000;
goku.styleMark = "亀";
goku.styleName = "亀仙流";

そして最後に、show メソッドを2回呼び出しています。

goku.show();
goku.show();

実行結果は次のようになります。

戦士の名前は悟空です。
戦闘力は9000です。
流派の印は「亀」です。
流派名は亀仙流です。
戦士の名前は悟空です。
戦闘力は9000です。
流派の印は「亀」です。
流派名は亀仙流です。

同じ show メソッドを2回呼び出しているため、同じ内容が2回表示されます。

ここで大事なのは、show メソッドを書いただけでは表示されないということです。
goku.show(); と呼び出した瞬間に、show メソッドの中の処理が実行されます。

メソッド呼び出しの流れを丁寧に見る

Sample2.java の処理の流れを追うと、次のようになります。

順番処理
1main メソッドの処理が始まる
2goku オブジェクトを作る
3goku.name、goku.power、goku.styleMark、goku.styleName に値を入れる
4goku.show() に到達する
5show メソッドの中へ移る
6show の中の処理を上から順番に実行する
7show が終わると、呼び出し元の main に戻る
8次の goku.show() が実行される
9もう一度 show の中の処理が行われる

メソッドは、ひとまとまりの処理に移動して、終わったら呼び出し元に戻るしくみです。

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

悟空、戦士情報を表示してくれ

と命じると、悟空が自分の名前、戦闘力、流派を伝え、終わったらまた次の処理に戻るような感覚です。

クラスの外ではオブジェクト名をつけてフィールドにアクセスする

main メソッドのように、クラスの外側からフィールドにアクセスするときは、どのオブジェクトのフィールドなのかをはっきり示す必要があります。

そのため、次のように書きます。

goku.name = "悟空";
goku.power = 9000;
goku.styleMark = "亀";
goku.styleName = "亀仙流";

ここでは、次の意味になります。

書き方意味
goku.namegoku が参照するオブジェクトの name
goku.powergoku が参照するオブジェクトの power
goku.styleMarkgoku が参照するオブジェクトの styleMark
goku.styleNamegoku が参照するオブジェクトの styleName

もしオブジェクト名をつけなければ、どの戦士の name なのか分かりません。

悟空なのか、ベジータなのか、悟飯なのかを区別するために、クラスの外ではオブジェクトを指定する必要があります。

場所書き方意味
クラス外goku.namegoku が参照するオブジェクトの name
クラス外goku.powergoku が参照するオブジェクトの power
クラス外goku.styleMarkgoku が参照するオブジェクトの styleMark
クラス外goku.styleNamegoku が参照するオブジェクトの styleName

クラスの外から見ると、オブジェクトは複数ある可能性があります。
だから「どのオブジェクトのメンバなのか」を明示する必要があります。

クラスの内側では自分自身のフィールドをそのまま書ける

一方、Saiyan クラスの中にある show メソッドでは、次のように書いています。

System.out.println("戦士の名前は" + name + "です。");
System.out.println("戦闘力は" + power + "です。");
System.out.println("流派の印は「" + styleMark + "」です。");
System.out.println("流派名は" + styleName + "です。");

ここでは、goku.name や goku.power のように、オブジェクト名をつけていません。

それでも意味が通るのは、この show メソッドが、そのとき処理されているオブジェクト自身の中で動いているからです。

つまり、show の中で書かれた name、power、styleMark、styleName は、次の意味になります。

書き方意味
name今 show が動いているオブジェクト自身の name
power今 show が動いているオブジェクト自身の power
styleMark今 show が動いているオブジェクト自身の styleMark
styleName今 show が動いているオブジェクト自身の styleName

今回なら、goku.show() と呼び出しているため、show の中の name は goku オブジェクトの name を表します。
show の中の power は goku オブジェクトの power を表します。
show の中の styleMark は goku オブジェクトの styleMark を表します。
show の中の styleName は goku オブジェクトの styleName を表します。

クラスの内側では、自分自身のフィールドにアクセスしているので、フィールド名だけで書けるのです。

this をつけると自分自身を強調できる

クラスの中では、フィールド名だけでなく、this. をつけて書くこともできます。

show メソッドは、次のようにも書けます。

void show()
{
    System.out.println("戦士の名前は" + this.name + "です。");
    System.out.println("戦闘力は" + this.power + "です。");
    System.out.println("流派の印は「" + this.styleMark + "」です。");
    System.out.println("流派名は" + this.styleName + "です。");
}

this は、そのメソッドが動いている自分自身のオブジェクトを表します。

つまり、次のような意味になります。

書き方意味
this.name自分自身の name
this.power自分自身の power
this.styleMark自分自身の styleMark
this.styleName自分自身の styleName

今の段階では、毎回 this をつけなくても大丈夫です。

ただし、this. をつけることで「自分自身のフィールドを使っている」ということが、よりはっきり見えます。

図:メソッドを呼び出すと処理が動き出す

この図が示していること

この図は、メソッドが「定義しただけでは動かない」ことを示しています。

Saiyan クラスの中には、name、power、styleMark、styleName というフィールド、そして show() というメソッドがあります。

右側の goku.show(); によって show() が呼び出されると、メソッドの中の表示処理が実行されます。

この図から分かることは、メソッドはクラスの中に用意しておくだけではなく、オブジェクトを通して呼び出すことで実際に動くということです。

クラスの中から別のメソッドを呼び出せる

メソッドは、main メソッドのようなクラスの外側から呼び出すだけではありません。

同じクラスの中にある別のメソッドから呼び出すこともできます。

これはとても便利な考え方です。

ドラゴンボールで言えば、ある行動の中で別の技を続けて発動するようなものです。

たとえば、showSaiyan メソッドで「これからサイヤ人戦士の情報を表示します」と案内し、そのあと show メソッドを呼び出して本当に情報を表示する、という流れを作れます。

メソッドからメソッドを呼び出すプログラム

ファイル名:Sample3.java

class Saiyan
{
    String name;
    int power;
    String styleMark;
    String styleName;

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("流派の印は「" + styleMark + "」です。");
        System.out.println("流派名は" + styleName + "です。");
    }

    void showSaiyan()
    {
        System.out.println("これからサイヤ人戦士の情報を表示します。");
        show();
    }
}

class Sample3
{
    public static void main(String[] args)
    {
        Saiyan goku;

        goku = new Saiyan();

        goku.name = "悟空";
        goku.power = 9000;
        goku.styleMark = "亀";
        goku.styleName = "亀仙流";

        goku.showSaiyan();
    }
}

このプログラムでは、Saiyan クラスに showSaiyan という新しいメソッドが追加されています。

void showSaiyan()
{
    System.out.println("これからサイヤ人戦士の情報を表示します。");
    show();
}

showSaiyan の中では、まず案内メッセージを表示しています。

System.out.println("これからサイヤ人戦士の情報を表示します。");

そのあとで、show メソッドを呼び出しています。

show();

実行結果は次のようになります。

これからサイヤ人戦士の情報を表示します。
戦士の名前は悟空です。
戦闘力は9000です。
流派の印は「亀」です。
流派名は亀仙流です。

showSaiyan が呼ばれると、まず案内メッセージが表示されます。
そのあと、show の処理に進み、戦士の名前、戦闘力、流派の印、流派名が表示されます。

クラス内でメソッド名だけを書ける理由

Sample3.java の showSaiyan メソッドでは、次のように書かれています。

show();

ここでは、goku.show(); のようにオブジェクト名をつけていません。

これは、showSaiyan も show も、同じオブジェクト自身の中で動いているメソッドだからです。

つまり、showSaiyan の中から show を呼ぶときは、

今この処理をしている自分自身の show を呼ぶ

という意味になります。

そのため、クラス内ではメソッド名だけで呼び出せます。

これはフィールドと同じ考え方です。

場所書き方意味
クラス外goku.show()goku が参照するオブジェクトの show を呼ぶ
クラス内show()自分自身の show を呼ぶ

クラスの外では、どのオブジェクトのメソッドかを指定する必要があります。
クラスの内側では、自分自身のメソッドなので、名前だけで呼び出せます。

メソッドにも this をつけられる

メソッドも、フィールドと同じように this. をつけて呼び出せます。

たとえば showSaiyan の中は、次のようにも書けます。

void showSaiyan()
{
    System.out.println("これからサイヤ人戦士の情報を表示します。");
    this.show();
}

ここでの this.show() は、自分自身の show メソッドを呼び出しているという意味です。

書き方意味
show()自分自身の show を呼び出す
this.show()自分自身の show であることを明示して呼び出す

この場面では、show() と this.show() はほぼ同じ意味です。

ただし、this. をつけることで「自分自身のメソッドを呼んでいる」と分かりやすくなります。

外からのアクセスと内側からのアクセスを整理する

クラスの外側からアクセスするときと、クラスの内側からアクセスするときでは、書き方が変わります。

フィールドの場合

場所書き方意味
クラス外goku.namegoku が参照するオブジェクトの name
クラス外goku.powergoku が参照するオブジェクトの power
クラス内name自分自身の name
クラス内power自分自身の power
クラス内this.name自分自身の name を明示
クラス内this.power自分自身の power を明示

メソッドの場合

場所書き方意味
クラス外goku.show()goku が参照するオブジェクトの show を呼ぶ
クラス外goku.showSaiyan()goku が参照するオブジェクトの showSaiyan を呼ぶ
クラス内show()自分自身の show を呼ぶ
クラス内this.show()自分自身の show を明示して呼ぶ

この整理が頭に入ると、クラスの外と内で書き方が変わる理由がすっきり見えてきます。

ドラゴンボールで言えば、外から悟空に命令するときは「悟空、状態を表示して」と誰に命令するかを指定します。
一方で、悟空本人が自分の中で動いているときは、「自分の名前」「自分の戦闘力」「自分の流派」と分かるので、わざわざ外から指定する必要がありません。

図:クラスの中から別のメソッドを呼び出す

この図が示していること

この図は、メソッドの中から別のメソッドを呼び出す流れを示しています。

goku.showSaiyan() が呼び出されると、まず showSaiyan() の処理が動きます。
showSaiyan() の中では案内メッセージを表示し、そのあと show() を呼び出します。
show() では、name、power、styleMark、styleName を使って戦士の情報を表示します。

この図から分かることは、メソッドは単独で使うだけでなく、別のメソッドと組み合わせて処理を作れるということです。

また、クラスの中では show() のようにメソッド名だけで、自分自身のメソッドを呼び出せることも分かります。

必殺技としてメソッドを見ると理解しやすい

メソッドという言葉が少しかたく感じるときは、ドラゴンボールの世界観で「必殺技」や「動作」と考えると分かりやすいです。

たとえば、show は「戦士が自分の状態を表示する技」です。
showSaiyan は「案内してから状態表示につなぐ技」です。

このように考えると、メソッドとは次のようなものだと見えてきます。

メソッドの見方内容
処理のまとまり複数の処理をひとつにまとめる
必要なときに呼び出すものshow() のように呼ぶと動く
クラスの中に定義する機能オブジェクトが持つ動きになる

フィールドだけがあるクラスは、プロフィールだけが書かれた戦士カードのようなものです。

そこにメソッドが加わると、その戦士は自分の情報を表示したり、別の処理を呼び出したりできるようになります。

ここに、オブジェクト指向らしいおもしろさがあります。

いちばん大事な感覚

メソッドを作って使うときに大切なのは、次の流れです。

ポイント内容
メソッドを定義するまとまった処理をクラスの中に書く
オブジェクトを作るそのオブジェクトのメソッドを使えるようにする
クラス外から呼び出すgoku.show() のようにオブジェクト名をつける
クラス内から呼び出すshow() のように名前だけで呼び出せる
this を使う自分自身のフィールドやメソッドだと明示できる

ドラゴンボールで言いかえるなら、悟空には name、power、styleMark、styleName のような情報があります。
さらに show や showSaiyan のような行動も持てます。

goku.showSaiyan() と呼び出すと、その行動が実際に発動します。
行動の中で、別の行動 show() を呼び出すこともできます。

ここまで理解できると、クラスは「情報を持つ箱」から、「情報と動きをまとめた部品」へと見え方が変わってきます。

この感覚は、この先に学ぶ引数、戻り値、コンストラクタ、継承へとつながっていきます。