Javaによるプログラミング入門12
値を返すメソッド

 こんにちは。今日は、「値を返すメソッド」あるいは「メソッドの返す値」についての話をします。この話は、はやくしなければと思いつつなかなかできなかった話です。
 Javaでは、一般に何かするもののことをメソッドと言うのでした。そして、メソッドは一般に「値を返す」のです。(または「戻す」などとも言います。)...と言われても、何のことかわからないですね。わからないのが正常です。ゆっくりいきましょう。
 実は、メソッドを使うと、普通のメソッドはその「場所」に何かを残していく(あるいは、報告していく)のです。その残していくものを「メソッドの返り値(戻り値)」などというのです。では、どのような値を返すかというと、それはメソッドの作者が決める値なのです。
 また、値を返さないメソッドもあります。実は今まで我々がつくったメソッドはすべて値を返さないメソッドだったのです。そして、「値を返さない」と宣言しているのが、メソッドの前のvoidだったのです。
 入門5のプログラムInuSample.javaをもう一度みてみましょう。コンストラクタの前には何もついていません。コンストラクタとはそういうものなのです。メソッドnaku()の前にはvoidがあります。気になっていた人も多いでしょうね。これが、このメソッドが何も返さない(あるいは「報告しない」)という意味の宣言だったのです。voidとは「無」という意味ですね。
 今回は、このような「値を返さないメソッド」ではなく「値を返すメソッド」を紹介します。

 まず、簡単な例で見ていきましょう。下のプログラムをみてください。

//Ex1.java
class X
{
    void method(){
        System.out.println("こんにちは。私はXのオブジェクトです。");
    }
}

class Ex1
{
    public static void main(String[] args){
        X x = new X();
        x.method();
    }
}

 上のプログラムでは、まずクラスXを定義し、そのメソッドとしてmethodを定義しています。メソッドと言ってもただ「こんにちは。私はXのオブジェクトです。」と画面に表示するだけのメソッドです。いつものように、頭にvoidがついていますね。
 そして、クラスEx1のmainの中に「x.method();」と書いてありますが、ここでXのメソッドmethodを実行しているわけですね。

Fig.1 Ex1の実行

 このようなプログラムはさんざん書いてきたので難しくはないですよね。まずは、小手調べです。

 さて、ここで、上のプログラムを次のように変えてみます。

//Ex2.java
class X
{
    int method(){
        System.out.println("こんにちは。私はXのオブジェクトです。");
        return 1;
    }
}

class Ex2
{
    public static void main(String[] args){
        X x = new X();
        x.method();
    }
}

 上のプログラムを実行すると、結果ははじめのものと全く同じになります。しかし、プログラムの意味は少し違うのです。まず、methodの定義の前がvoidではなくintであることに注意してください。これは「intすなわち、整数を返すメソッドである」という意味です。どこに返すかというとこのメソッドを呼び出した「場所」に返すのです。そして、このメソッドの定義の一番下の行にある「return 1;」が実際に返す値を決めているのです。これは、「数値1を返す」という意味です。(注:返すというと「借りたものを返す」という感じにとれますが、ここではそうではありません。誰もどこからも何も借りていませんので。ただ、「呼び出した場所に整数を置いてくる」というような意味で「返す」という言葉を使っているのです。これはreturnの日本語訳です。はじめに書いたように、他の言語などで「戻す」ということもありますが意味は同じです。)
 では、この返された値1はプログラム中でどのようにつかわれているでしょうか?実は、全く使われていません。main内でXのmethodが呼ばれているので「System.out.println("こんにちは。私はXのオブジェクトです。");」はちゃんと実行されるのですが、返された値は何の役も果たしていないのです。
 もし、返された値をちゃんと表示したければ、たとえば、mainのあるクラスを次のように書き直せばよいのです。

//Ex3.java
class X
{
    int method(){
        System.out.println("こんにちは。私はXのオブジェクトです。");
        return 1;
    }
}

class Ex3
{
    public static void main(String[] args){
        int d;  //整数変数dの宣言(「整数dを使うよ」という意味)
        X x = new X();
        d = x.method();//考え込むと不思議な文ですが、次のような意味になります。
                //まず、Xのmethodの中身が実行される。
               
//そして、このメソッドから返された値1がdに代入される。
        System.out.println("methodから返された値=" + d);  //dの値の出力
    }
}

 ここで、「d = x.method();」は不思議な文ですが、これで、Xのmethodの中身がまず実行され、次に値1が返され、それがdに代入されることになるのです。ここでいう「返される」とは、実質的には、このメソッドx.methos()が実行されたあと、x.method()と書いてあるところが数値1に変わるということなのです。
 実際実行してみてください。まず、画面に「こんにちは。私はXのオブジェクトです。」と出力され、その後に(と言っても,人間の目にその順序は見えませんが)数値1が画面に出力されて終わりになります。

Fig.2 Ex3の実行

 Ex2.javaとEx3.javaの違いは、単に、返された値を使うか使わないかの違いです。このように返された値を使う使わないはプログラマの自由なのです。

 上の例はあまりにも無意味な例だったので、Xに「二つの整数値を引数に取って、その合計を返す」メソッドをつくって、そのメソッドを使うプログラムを書いてみましょう。

//TasizanEx.java
import java.io.*;

class X
{
    int add() throws IOException{
        String s;
        BufferedReader br =
          new BufferedReader(new InputStreamReader(System.in));

        int a, b;  //二つの整数をいれる変数
        System.out.println("これから二つの整数の足し算をします。");
        System.out.println("まず、ひとつめの整数を入力してください。");
        s = br.readLine();    //sにユーザの入力文字列を格納
        a = Integer.parseInt(s);
        System.out.println("もうひとつの整数を入力してください。");
        s = br.readLine();    //sにユーザの入力文字列を格納
        b = Integer.parseInt(s);
        //次のreturnで合計を返す
        return a + b;
    }
}

class TasizanEx
{
    public static void main(String[] args) throws IOException{
        X x = new X();
        int d = x.add();//整数変数dが宣言され、すぐにx.add()が実行され、その返す値がdに代入される。
        System.out.println("合計:" + d);
    }
}

Fig.3 tasizan.exe

 この例のように、返り値(戻り値)は定数である必要はないのです。


 それでは、初心者には少し難しい問題をひとつ。できなくても大丈夫です。とても熱心な人は今までの復習をしながら考えてみてください。それほど熱心でもない普通の人は、ちょっと考えてから、答えを眺めてみてください。

問題:
入門5の犬を次のように改良したクラスをつくってください。

  クラス 犬
    データメンバ:名前
           体力(整数)
    コンストラクタ:名前を受け取り、はじめの体力を10とする       
    メンバメソッド :食事をもらう(もらってたべた量だけ体力を増やすメソッド)  
           鳴く(鳴いて、体力を5減らす)       
 ただし、メソッド「食事」と「鳴く」は実行後の体力を「返り値」で報告するものとします。

解答例:
class Inu
{
    private String name;
    private int tairyoku;
    Inu(String s){
        name = s;
        tairyoku = 10;
    }
    int syokuji() throws IOException{
        System.out.println(name + "に食事をさせます。どれだけ食べさせますか?);
        String s;
        BufferedReader br =
          new BufferedReader(new InputStreamReader(System.in));
        int food = Integer.parseInt(s);
        tairyoku += food; 
        return tairyoku;   //tairyokuの値を返す
    }
    int naku(){
        System.out.println("わん。僕は" + name + "だ。");
        tairyoku -= 5; 
        return tairyoku;   //tairyokuの値を返す
    }
}

 「tairyoku += food;」は「tairyokuにfoodを足せ」、「tairyoku -= 5;」は「tairyokuから5引け」という意味でしたね。ポイントはsyokuji、nakuメソッドの前にintがあり、それらの定義の最後にはreturn文があるということです。

 このクラスを使ったプログラム例は次のようなものでしょう。

//InuSample4.java
import java.io.*;
class Inu
{
    private String name;
    private int tairyoku;
    Inu(String s){
        name = s;
        tairyoku = 10;
    }
    int syokuji() throws IOException{
        System.out.println( name + "に食事をさせます。どれだけ食べさせますか?");
        String s;
        BufferedReader br =
          new BufferedReader(new InputStreamReader(System.in));
        s = br.readLine();
        int food = Integer.parseInt(s);
        tairyoku += food;
        return tairyoku;   //tairyokuの値を返す
    }
    int naku(){
        System.out.println("わん。僕は" + name + "だ。");
        tairyoku -= 5;
        return tairyoku;   //tairyokuの値を返す
    }
}

class InuSample4
{
    public static void main(String[] args) throws IOException{
        System.out.println("犬をメモリ上に生成します。名前を決めてください。");
        String s;
        BufferedReader br =
          new BufferedReader(new InputStreamReader(System.in));
        s = br.readLine();
        Inu kai_inu = new Inu(s);  //飼い犬の生成 名はユーザがsに入力したもの
        System.out.println();    //見やすさのための改行
        for(int i = 0; i < 5 ;i++){  //5回だけメモリ上の犬と遊ぶプログラムです
            System.out.println("どうします?");
            System.out.println("1 食事を与える 2 鳴かす");
            s = br.readLine();
            int ans = Integer.parseInt(s);
            if(ans == 1){
                int t;
                t = kai_inu.syokuji();  //まず、Inuのsyokujiの内容が実行され、その結果の体力が
                //Inuのsyokujiの返り値として与えられ、tに代入される。
                System.out.println("犬の体力=" + t);
            }
            else if(ans == 2){
                int t;  //上のtとは別の{ }ブロック内にあるので全く無関係
                t = kai_inu.naku();  //まず、Inuのnakuの内容が実行され、その結果の体力が
                //Inuのnakuの返り値として与えられ、tに代入される。
                System.out.println("犬の体力=" + t);
                if(t < 0){
                    System.out.println("食事が不十分だったので、犬はストライキをしてしまいました。");
                    break;  //for文からぬけろという命令 体力が負になったらおしまいということです
                }    //if(t < 0)のかっこ閉じる
            }        //if(ans==2)のかっこ閉じる
            System.out.println(); //見やすさのための改行
        }            //for(i=0;i<5;i++)のかっこ閉じる
        System.out.println("おわり");
    }
}

 途中ででてきた「System.out.println();」は、単に改行せよという意味です。
 できれば、このくらいのプログラムをなんとか読んで理解できるようにしてください。(きびしいでしょうか?)自分で書けなくても読んで理解できるというところが今日の目標です。

Fig.4 InuSample4の実行(育てゲーも夢じゃない?)


 ところで、気が付いていましたか?プログラムの中心のmainもよく見ると、メソッドの定義と同じ形をしていますね。

class X
{
    public static void main(){
        ...
   
}

 実は、mainは、プログラムの中心を表わすメソッドなのです。そして、mainは「値を返さないメソッド」なので前にvoidがあるのです。一番前にあるpublicは、まだあまり詳しく説明していませんが「公開」などという意味でした。その次のstaticはまた後で説明しますので、今は、あまり気にしないでおいてください。とにかく、mainもメソッドなのです。


 返り値にはいろいろなものがあるのですが、今回はこの辺にしておきましょう。
 このような値を返すメソッドは,たとえば、前の「魔王とヒーローの対決」で、魔王とヒーローの対決を複数回にするときなどにも使えます。次回にゆっくりやってみましょうか。
目次のページ
前のページ  次のページ