Java入門|必殺技(メソッド)を作って使う

技を覚えるだけでは終わらない。メソッドを作って呼び出すと、クラスは本当に動き出す

ここまでで、クラスの中にはフィールドを用意できること、そしてクラスからオブジェクトを作って、そのフィールドに具体的な値を入れられることを学んできました。けれども、オブジェクト指向の面白さは、情報を持たせることだけではありません。クラスの中に「動き」もまとめられるところに、大きな魅力があります。

Javaでは、その動きをメソッドで表します。ドラゴンボールで考えるなら、戦士が持っている名前や戦闘力がフィールドなら、かめはめ波を放つ、状態を表示する、仲間に合図する、といった行動がメソッドです。つまりメソッドは、クラスにとっての「機能」や「必殺技」をまとめるためのしくみだと考えると、とてもわかりやすいです。

ここでは、メソッドをどう定義するのか、どう呼び出すのか、そしてクラスの外と内でメンバへのアクセス方法がどう変わるのかを、ドラゴンボールの世界に置きかえながら、順番にやさしく整理していきます。

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

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

たとえば、サイヤ人クラスを考えたとき、フィールドには次のような情報が入ります。

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

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

種類内容
メソッドshow、showSaiyan など

ドラゴンボールで言えば、戦士には「名前がある」「戦闘力がある」という状態だけでなく、「自分の情報を表示する」「戦う準備を伝える」といった行動があります。
この行動をまとめる場所がメソッドです。

つまりクラスは、

  • 情報を持つ
  • 動きを持つ

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

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

メソッドは、あるまとまった処理をひとつの名前でくくるためのしくみです。
たとえば、「戦士の情報を表示する」という処理を毎回長く書くのではなく、show というメソッドにまとめておけば、必要なときにその名前を使うだけで同じ処理を実行できます。

イメージとしては、次のような形です。

void show()
{
    System.out.println("戦士の名前は" + name + "です。");
    System.out.println("戦闘力は" + power + "です。");
}

この show というメソッドには、2つの表示処理がまとまっています。
ドラゴンボールで考えると、これは「自分の戦士情報を見せる技」をひとつにまとめたようなものです。

ここでまず押さえておきたいのは、メソッドには名前があり、その中に複数の文を入れられるということです。
これによって、同じ処理を何度も使いやすくなります。

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

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

表で整理するとこうです。

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

たとえば Saiyan クラスなら、

  • name
  • power
  • specialMove

はフィールドです。

一方で、

  • show
  • showSaiyan

はメソッドです。

どちらもクラスを構成する大切な部品ですが、役目が違います。
フィールドは状態を表し、メソッドは動きを表します。
この違いをはっきり意識しておくと、コードがかなり読みやすくなります。

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

ここではまず、戦士の情報を表示するメソッドを考えてみましょう。
ドラゴンボールのたとえに合わせて、Car の show を Saiyan の show として組み立てると、次のような形になります。

class Saiyan
{
    String name;
    int power;

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
    }
}

このクラスの中では、

  • name
  • power

というフィールドに加えて、

  • show

というメソッドが定義されています。

show の中を見ると、name と power を使ってメッセージを表示しています。
ここがとても大切なポイントです。メソッドは、クラスの中にあるフィールドを使って処理を行えるのです。

ドラゴンボールで言いかえるなら、その戦士が持っている名前や戦闘力をもとにして、自分の情報を名乗っているイメージです。

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

メソッドは定義しただけではまだ動きません。
実際にその処理を行うには、メソッドを呼び出す必要があります。

メソッドの呼び出しは、オブジェクトをさす変数名に . をつけて、メソッド名と () を書く形になります。

たとえば、goku が Saiyan オブジェクトを参照しているなら、

goku.show();

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

この書き方は、フィールドアクセスとよく似ています。

  • goku.name はフィールドへのアクセス
  • goku.show() はメソッドの呼び出し

という違いです。

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

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

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

ファイル名:Sample2.java

class Saiyan
{
    String name;
    int power;

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
    }
}

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

        goku.name = "悟空";
        goku.power = 9000;

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

このプログラムでは、まず Saiyan クラスの中で show メソッドを定義しています。
そのあと main メソッドで goku というオブジェクトを作り、name と power に値を入れています。
そして最後に、goku.show(); を2回呼び出しています。

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

戦士の名前は悟空です。
戦闘力は9000です。
戦士の名前は悟空です。
戦闘力は9000です。

同じメソッドを2回呼び出したので、同じ内容が2回表示されます。

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

メソッドの呼び出しで大事なのは、処理がどのように流れるかです。

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

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

この流れがわかると、メソッドは「ひとまとまりの処理にジャンプして、終わったら元に戻る」しくみだと見えてきます。

ドラゴンボールでたとえるなら、
「悟空、情報を表示してくれ」
と呼びかけると、悟空が自分の情報を話し終えるまでその処理が進み、終わったらまた元の流れに戻るような感覚です。

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

main メソッドのように、クラスの外側からフィールドにアクセスするときには、どのオブジェクトのフィールドなのかをはっきり示さなければいけません。

だから、次のように書きます。

goku.name = "悟空";
goku.power = 9000;

ここでは、

  • goku の name
  • goku の power

という意味になっています。

もしオブジェクト名をつけなければ、どの戦士の name なのかがわかりません。
悟空なのか、ベジータなのか、悟飯なのかを区別するために、クラスの外では必ずオブジェクトを指定する必要があります。

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

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

System.out.println("戦士の名前は" + name + "です。");
System.out.println("戦闘力は" + power + "です。");

ここでは goku.name や goku.power のように、オブジェクト名をつけていません。
それでも意味が通るのは、このメソッドがそのとき処理されているオブジェクト自身の中で動いているからです。

つまり show の中で書かれた name や power は、

  • 今 show が動いているそのオブジェクトの name
  • 今 show が動いているそのオブジェクトの power

を表しています。

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

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

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

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

void show()
{
    System.out.println("戦士の名前は" + this.name + "です。");
    System.out.println("戦闘力は" + this.power + "です。");
}

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

つまり、

  • this.name
  • this.power

は、自分自身の name と power という意味です。

今の段階では、無理に every time this を使わなくても大丈夫です。
ただ、クラス内ではフィールド名だけでも書けるし、this. をつけて自分自身だと強調することもできるということは、ここで覚えておくと役に立ちます。

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

メソッドは、main メソッドのようなクラスの外側から呼び出すだけでなく、同じクラスの中にある別のメソッドから呼び出すこともできます。

これも、とても便利な考え方です。
ドラゴンボールで言えば、「これから情報を表示するぞ」と言ってから、本当に情報を表示する処理を呼び出すような流れです。

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

ファイル名:Sample3.java

class Saiyan
{
    String name;
    int power;

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
    }

    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.showSaiyan();
    }
}

このプログラムでは、Saiyan クラスに showSaiyan という新しいメソッドが追加されています。
そして、その中で show(); を呼び出しています。

実行結果はこうなります。

これから戦士の情報を表示します。
戦士の名前は悟空です。
戦闘力は9000です。

showSaiyan が呼ばれると、まず案内のメッセージが表示され、そのあとで show の処理へ進みます。

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

showSaiyan の中では、show(); とだけ書かれていて、goku.show(); のようには書かれていません。

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

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

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

という意味になります。

そのため、クラス内ではメソッド名だけを書けば十分です。

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

場所書き方
クラス外goku.show()
クラス内show()

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

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

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

たとえば showSaiyan の中は、こう書くこともできます。

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

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

つまり、

  • show()
  • this.show()

は、この場面ではほぼ同じ意味になります。

ただし、this. をつけることで「自分自身のメソッドを呼んでいるんだな」ということが、よりはっきり見えるようになります。

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

ここまでの内容を表で整理すると、とても見やすくなります。

フィールドの場合

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

メソッドの場合

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

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

この図では、左側に Saiyan クラスの中身がまとまっていて、上にフィールド、下にメソッドが配置されています。
これによって、クラスの中に「情報」と「機能」の両方があることが目で見てわかります。

右側には goku.showSaiyan() という呼び出しがあり、そこから showSaiyan() に処理が移り、さらにその中で show() が呼ばれている流れが矢印で示されています。
これを見ると、メソッドはただ書かれているだけではなく、呼び出されることで実際に動き出すことが理解しやすくなります。

また、下部の実行結果を見ることで、案内メッセージのあとに戦士の情報が表示されるという流れもつかみやすくなります。

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

メソッドという言葉がまだ少しかたく感じるときは、ドラゴンボールらしく「必殺技」や「機能」と考えるとわかりやすいです。

たとえば show は、戦士が自分の状態を見せる技です。
showSaiyan は、その前にひと言案内を出してから状態表示へつなぐ技です。

このように考えると、メソッドとは

  • 処理をひとまとめにしたもの
  • 必要なときに呼び出して使うもの
  • クラスの中に定義する機能

だとイメージしやすくなります。

クラスにフィールドだけがある状態は、プロフィールだけが書かれた戦士のカードのようなものです。
そこにメソッドが加わると、その戦士が実際に行動できるようになります。
ここに、オブジェクト指向らしい面白さがあります。

いちばん大事な感覚

「必殺技(メソッド)を作って使う」で大切なのは、次の流れです。

  • メソッドは、まとまった処理をクラスの中に定義するしくみ
  • オブジェクトを作ると、そのオブジェクトのメソッドを呼び出せる
  • クラス外では、オブジェクト名をつけて呼び出す
  • クラス内では、自分自身のメソッドやフィールドを名前だけで使える
  • 必要に応じて this. をつけて、自分自身であることを明示できる

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

  • 戦士には name や power のような情報がある
  • さらに show や showSaiyan のような必殺技も持てる
  • goku.showSaiyan() と呼び出すと、その技が実際に発動する
  • 技の中で別の技を呼ぶこともできる

ということです。

ここまで理解できると、クラスは「情報を持つ箱」から、「情報と動きをまとめた部品」へと見え方が変わってきます。
そしてその感覚は、この先に学ぶ引数、戻り値、コンストラクタ、継承へとつながっていきます。