Javaによるプログラミング入門7
クラスの練習

 こんにちは。はやいもので、もう、5月ですね。

 私は多くのことが、わかろうと考え込むより、やってみる方がわかるのでは、と思っています。たとえば、プログラムの場合、「コンパイル・実行」->「改造」->「コンパイル・実行」->「改造」->・・・を繰り返すのがよいと思うのです。
 はじめは単純なタイプミスでコンパイルエラーがでますが、そのうち、タイプミスはすぐに探せるようになります。そうこうしているうちに、おっかなびっくりでなく(簡単な)プログラムが作れるようになってきます。そしてわかったような気がしてくるから、不思議です。

 なお、なるべく自分でタイプしてみた方が勉強になると思いますが、時間がないときなどは、このページのサンプルをコピーして、コンパイル・実行するのもありです。動いているプログラムを見ることだけでも、「慣れる」という意味があるからです。それから、少し改造してみてください。
 そのような目的もあるため、私のページのサンプルはそのままコピーして使えるように書いているつもりです。しかし、いろいろな事情で、プログラムに使えない(しかも目に見えない)文字が紛れ込むこともあるようです。その場合は、ご連絡いただければ幸いです。


 mainを持つクラス以外のクラスには納得がいったでしょうか?それはとりあえず認めてもらうことにして、今回は、復習しながら少し新しいこともまじえて、単純なクラスを作ってみましょう。前回までの分を読み直すより、まず、今回の分を最後のプログラムのところまでさっと読んでみてください。それから、前回までの分を読み直すのもよし、今回の分を精読するのもよしです。お勧めは、やっぱり、「プログラムをコンパイル・実行してみる」です。^^)

 さて、どんなクラスを作ってみましょうか?そんな風に考えるのもたのしいですよね。今日は「ロケット」をつくってみます。ロケットの持つべき「データ」(つまり、フィールド)と「動作・機能」(つまりメソッド)は何でしょうか?私なら、次のように考えます。

    クラス ロケット
    フィールド :燃料
           現在の速度
    メソッド  :加速

 まあ、はじめはこんなもんでしょう。ロケットに名前をつけたい、発射の仕掛けもつくりたい、など、要望は多々あると思いますが、はじめは簡単にします。
 前に書いたように、基本的に、フィールドはprivateにします。そして、燃料と速度は、簡単に整数としましょう。するとintを使えばいいですね。それぞれをnenryo、sokudoとします。

 それから、コンストラクタを考えましょう。クラスには必ずコンストラクタを書かなければならない、というわけではありません。しかし、たいていの場合必要になります。ということで、ロケットのクラスにもコンストラクタを付けます。(コンストラクタを書かない場合については、また回を改めて説明します。)
 コンストラクタに書くことは、基本的に、「生成されるオブジェクトにどのようなデータを与えるか」が中心です。「犬」のときは名前を与えました。このようにメンバ変数の値を決めてやるのがコンストラクタの主な仕事なのです。これをオブジェクトの初期化なんて言います。「オブジェクト」はメモリ上の「もの」(具体的な「犬」や「ロケット」)という意味でした。「初期化」とは一般に「データなどをはじめに決めてやる」という意味なのです。さあ、どう初期化しましょうか。たとえば、燃料を引数で決めてやって、速度を0にすればいいでしょう。
(「コンストラクタ」も「引数」も初心者にはわかりにくいですね。上に書いたように「コンストラクタ」はオブジェクトを生成するときに使うものです。「引数」はコンストラクタなど関数のかっこの中にいれるデータのことでした。ここで考え込まずに下の使用例を見てください。)
 加速のメソッドはどうしましょうか。加速は物理学の法則によると、、、なんてやめましょう。加速一回で速度が適当に(私は2とします。もちろん深い理由はないので別の数字でもかまいません)上がるようにします。そのとき、当然燃料が減るはずですね。同じ数(つまり2)だけ燃料が減るようにしましょう。以上をまとめると、ロケットのクラスRocketは次のようになります。

class Rocket        //スペルをまちがえるとかなり恥ずかしいので辞書を見ましょう
{
    private int nenryo;   
//燃料
    private int sokudo;   
//現在の速度
    //コンストラクタ
    Rocket(int x){
        nenryo = x;
        sokudo = 0;
    }
   
//加速を表すメソッド
    void kasoku(){
        sokudo += 2;
        nenryo -= 2;
    }
}

 いくつか新しいこととまだなじんでいないことがでてきたと思いますが、安心してください。ゆっくり説明します。そのための練習ですから。
 コンストラクタの定義では、nenryoにxを代入し、sokudoに0を代入しています。コンストラクタやメソッドに外から与えられるデータを引数というのでした。(あとで例を見ます。くどいですね。)コンストラクタの定義の「Rocket(int x)」の「int x」は、「引数を受け取ったらそれをxで表す」という意味です。(正確には、「引数の値をxにコピーする」です。)このように、コンストラクタやメソッドの定義の中で、引数を表す変数を仮引数と言ったり、パラメータと言います。この用語を使えば、「コンストラクタのxは仮引数」となるわけです。

 加速を表すメソッドkasoku()の前のvoidは、「何も報告しないで終わる」という程度の意味でした。(どこへ報告するのかは今は気にしないでください。いやですね、こういう言い方は。でもしかたがなかったなと、すぐに納得がいくはずです。)その定義の

sokudo += 2; 
nenryo -= 2;

は、変な式ですが、それぞれ「sokudoに2を足せ」「nenryoから2を引け」という意味になるのです。「+=」「-=」は、「右辺のものを左辺に足せ」「右辺のものを左辺から引け」という意味になると、そう決めてあるからです。(つまり、そういうものだと、ここでおぼえてください。)

 実はこれらは

sokudo = sokudo + 2;
nenryo = nenryo - 2;

と書くこともできます。数式としては変ですが、これは数式ではありません。「=」は代入を表すのです。したがって、たとえば上の式は、「nenryoにnenryo+2を代入せよ」つまり「nenryoに2を足せ」という意味になるのです。このような書き方より、「+=」「-=」を使う方が一般的ですが、これも理解しておくと、あとで役に立つはずです。
 ところでこのロケットは変です。燃料があってもなくても加速できるロケットですよね。これでは未来から来たネコ型ロボットのようです。燃料が切れたら、加速不可能になるように、kasoku()を書き直した方がよさそうです。
 そのようなときには、if文というものを使うのですが、まあ、答えを見てから考えましょう。

class Rocket     //改良版
{
    private int nenryo;    //燃料
    private int sokudo;    //現在の速度
    //コンストラクタ
    Rocket(int x){
        nenryo = x;
        sokudo = 0;
    }
    //kasokuを表すメソッド
    void kasoku(){
        if(nenryo >= 2){
            sokudo += 2;
            nenryo -= 2;
            System.out.println("現在の燃料は" + nenryo + "です。");
            System.out.println("現在の速度は" + sokudo + "です。");
        }
        else{
            System.out.println("燃料切れです。加速できません。漂流です。");
        }
    }
}

 kasoku()の中身は2つのブロックにわかれています。と、言っても最初はわからないでしょう。ifのブロック(ifの横の{から3行下の}まで)とelseのブロック(elseの横の{から2行下の}まで)です。ifのすぐあとの丸カッコ内の式「nenryo >= 2」は条件を表しています。ここは

  もし、nenryoが2以上ならば、

と読むのです。ここで、>=はイコールが下についた不等号のかわりです。(高校生が「大きいかまたは等しい」とかなんとかと読むやつです。)nenryoは一回の加速に2使うので、それが2以上なければ、もう燃料切れで加速できないと考え、そのチェックをしているのです。
 もちろん、もしnenryoが2以上なら、はじめに考えたようにsokudoに2を足し、nenryoから2を引きます。また、ついでにその時の燃料と速度を表示するようにしました。それがifのブロックに書いてあることです。
 elseは

  そうでなければ、

と読みます。つまり、ここでは「nenryoが2以上でなければ」という意味ですね。その場合は、燃料切れという意味ですから、ロケットは加速せず漂流としました。それがelseのブロックに書いてあることです。
 if文の一般的な形は、1番下にまとめますが、とりあえず、先に進みましょう。

 それでは、このRocketクラスを使った、またまた簡単なプログラムを書いてみます。ここでは、Rocketを使うため、mainを持つクラスRocketSampleを作ることにします。

//RocketSample.java
import java.io.*;

class Rocket      //改良版
{
    private int nenryo;    //燃料
    private int sokudo;    //現在の速度
    //コンストラクタ
    Rocket(int x){
        nenryo = x;
        sokudo = 0;
    }
    //kasokuを表すメソッド
    void kasoku(){
        if(nenryo >= 2){
            sokudo += 2;
            nenryo -= 2;
            System.out.println("現在の燃料は" + nenryo + "です。");
            System.out.println("現在の速度は" + sokudo + "です。");
        }
        else{
            System.out.println("燃料切れです。加速できません。漂流です。");
        }
    }
}

class RocketSample{
    public static void main(String[] args) throws IOException{
        BufferedReader br =
            new BufferedReader(new InputStreamReader(System.in));
        System.out.println( "ロケットをメモリ上につくります。燃料(整数)を入力してください。");
        String str = br.readLine();        //ユーザから入力を文字列として受け取る
        int n = Integer.parseInt(str);     //その文字列を整数に変換してnに格納

        //nをコンストラクタに渡してロケットをつくります。
        Rocket ohtori = new Rocket(n);
                  //これでnの値がコンストラクタの定義のxにコピーされ、
                  //コンストラクタの中身が実行され、nenryoの値がnの値に
                  //なったロケットが生成されるわけです。
                  //この変数ohtoriが生成されたRocketオブジェクトを指し示す(参照する)のです。
        System.out.println("加速します。");
        ohtori.kasoku();  //Ohotoriの指すオブジェクトに対してkasokuを使っています
        System.out.println("また、加速します。");
        ohtori.kasoku();  //Ohotoriの指すオブジェクトに対してkasokuを使っています
        System.out.println("またまた、加速してみます。");
        ohtori.kasoku();  //Ohotoriの指すオブジェクトに対してkasokuを使っています
        System.out.println("鳳号の冒険は終わりました。");
    }
}

Fig.1 RocketSampleの実行画面1(燃料をはじめに30にした)

Fig.2 RocketSampleの実行画面2(燃料をはじめに4にした)

 解説はあまりいらないと思うのですがどうでしょうか。RocketSampleのmainの中での、Rocketクラスの使い方をよく見ておいてください。

 なお、くどいですが、前回と同じコメントをしておきます。Javaでは、「Rocket ohtori = new Rocket(n);」でRocketオブジェクトが生成されるわけですが、Rocketの変数ohtoriは、「オブジェクトそのもの」を表すのではなく、「オブジェクトを指し示すもの」でした。(入門5も見ておいてください。関係ないですが、C++などでは、変数がオブジェクトそのものを表すと考えられますが、Javaではそうならないのです。C++プログラマは注意してください。)そして、「指し示す」をJava用語では「参照する」とも言うのでした。つまり、変数ohtoriは、「new Rocket(n);」で生成されたオブジェクトを参照するようになるのです。まだ、それがどうということはないのですが、徐々に頭に入れておいてください。

Fig.3 変数はオブジェクトを参照する(指し示す)

 鳳号(ohtoriの参照するオブジェクト)は3回加速していますね。もし、燃料切れにならなければ、速度が増えて、、、それだけです。もし、はじめの燃料がたりなければ、つまり、5以下なら、途中で漂流するでしょう。う〜ん。プログラムとしてはあんまりおもしろくないですね。(それでも、コンピュータが思いどうり動いてくれて、楽しいとは思うのですが、、、。)でも、まあ基礎ですから。基礎は飽きてきたという人、もう少し待ってください。


 

 最後に、if文のまとめを書いておきます。ざっとながめておいて、必要になったときに、見るようにしてもよいでしょう。

if文とは、一般に、

if(条件a){
    処理A
}
else if(条件b){
    処理B
}
  ...
else{
    処理Z
}

のような形をしています。このように書くと、「条件aが正しいとき処理Aが実行され、そうではなくて条件bが正しいときは処理Bが実行され、...となり、どの条件も正しくないときは、処理Zが実行される」というものです。ただし、ここで、「else if(...){...}」はいくつあっても(なくても)かまわないし、また、「else{...}」の部分は、なくてもかまいません。

 また、条件は次のように書きます。

aとbに対して、条件の書き方

a == b  aとbが等しい(とき)
a != b  aとbが等しくない(とき)
a < b   aがbより小さい(とき)
a <= b  aがbと等しいかbより小さい(とき)
a > b   aがbより大きい(とき)
a >= b  aがbと等しいかbより大きい(とき)


目次のページ
前のページ 後のページ