[目次] [前回] [次回] [重要語索引]

第3週: 部品を作る

3. 1 メソッド
3. 2 メソッドの呼び出し
3. 3 練習問題
3. 4 メソッドの引数
3. 5 練習問題
3. 6 メソッドの返り値
3. 7 練習問題
3. 8 宿題
3. 9 おまけ1
3.10 おまけ2

3.1 メソッド

Java のプログラムはメソッド(method)を単位としています。今までに書いたプログラムを思い出してみましょう。
    void sfcProcess () {
	//ここに自分のプログラムを書く
	sfcOutput("Hello World!");
    }
    void sfcDraw(Graphics g) {
	//ここに自分のプログラムを書く
	g.drawLine(0,0,300,300);
    }

上のような形をメソッド宣言と呼びます。一般には次のようになります。
    型 メソッド名(仮引数) {
         メソッドの内容
    }

Java のプログラムはたくさんのメソッドから成り立っています。これを全体から見ると、仕事を細かく分割して下請に発注していく仕組みと同じです。逆に個々のメソッドから見ると、単純な部品を組み合わせて複雑な機械を作るのと同じ仕組みです。

3.2 メソッドの呼び出し

メソッドは宣言しただけでは実行されません。呼び出されたときに実行されます。

method call

それでは、自分でメソッドを宣言し、呼び出してみましょう。まず、SfcTemplate2 をコピーして ManyFaces.java,ManyFaces.html を作ってください。
% cd 自分の作業ディレクトリ
% cp SfcTemplate2.java ManyFaces.java
% cp SfcTemplate2.html ManyFaces.html
%

とりあえず、プログラム名を変更します。
public class ManyFaces extends Applet implements ActionListener {
<applet code="ManyFaces.class" width=300 height=380>

新しいメソッドは sfcDraw の後、最後の「}」の前に書いてください。
45
46
47
48
49
50
51
52
53
54
55
56
    void sfcDraw(Graphics g) {
	//ここに自分のプログラムを書く
        face(g); //自分で作った face というメソッドを呼び出す
    }

    void face(Graphics g) {  //顔を描くメソッド
	g.drawRoundRect(10, 10, 80, 80, 20, 20);
	g.drawOval(20, 30, 20, 15);
	g.drawOval(60, 30, 20, 15);
	g.drawLine(50, 45, 50, 60);
	g.drawLine(40, 70, 60, 70);
    }

上のプログラムは、実は次のように書いても同じ結果になります。
45
46
47
48
49
50
51
52
    void sfcDraw(Graphics g) {
	//ここに自分のプログラムを書く
	g.drawRoundRect(10, 10, 80, 80, 20, 20);
	g.drawOval(20, 30, 20, 15);
	g.drawOval(60, 30, 20, 15);
	g.drawLine(50, 45, 50, 60);
	g.drawLine(40, 70, 60, 70);
    }
それでは、メソッドを別にする理由は何でしょうか?

3.3 練習問題

SfcTemplate1.java の中で、次の個所を探しなさい。
  1. sfcOutput() の宣言。
  2. sfcProcess() を呼び出しているところ。

3.4 メソッドの引数

上のプログラムで、同じ顔を右下にもう1個描くには、同じ図形を座標を (200, 200) ずらして描きます。

    g.drawRoundRect(10, 10, 80, 80, 20, 20);
    g.drawOval(20, 30, 20, 15);
    g.drawOval(60, 30, 20, 15);
    g.drawLine(50, 45, 50, 60);
    g.drawLine(40, 70, 60, 70);
    g.drawRoundRect(210, 210, 80, 80, 20, 20);
    g.drawOval(220, 230, 20, 15);
    g.drawOval(260, 230, 20, 15);
    g.drawLine(250, 245, 250, 260);
    g.drawLine(240, 270, 260, 270);

これは基準点が変わっているだけなので、次のように変数 x,y を基準にすれば、その値を変えることで、自由に位置を変えて描くことができます。

    g.drawRoundRect(x + 10, y + 10, 80, 80, 20, 20);
    g.drawOval(x + 20, y + 30, 20, 15);
    g.drawOval(x + 60, y + 30, 20, 15);
    g.drawLine(x + 50, y + 45, x + 50, y + 60);
    g.drawLine(x + 40, y + 70, x + 60, y + 70);

これをメソッドとして宣言しておけば、x, y の値を変えながら、何回も呼び出すことができます。
45
46
47
48
49
50
51
52
53
54
55
56
57
    void sfcDraw(Graphics g) {
	//ここに自分のプログラムを書く
	face(g, 0, 0);     // (0, 0) に顔を描く
	face(g, 200, 200); // (200, 200) に顔を描く
    }

    void face(Graphics g, int x, int y) {
	g.drawRoundRect(x + 10, y + 10, 80, 80, 20, 20);
	g.drawOval(x + 20, y + 30, 20, 15);
	g.drawOval(x + 60, y + 30, 20, 15);
	g.drawLine(x + 50, y + 45, x + 50, y + 60);
	g.drawLine(x + 40, y + 70, x + 60, y + 70);
    }

引数

3.5 練習問題

  1. forface の呼び出しを使って、次のような図を描くプログラムを作りなさい。

  2. face メソッドに倍率を表す引数を追加し、キーボードから 1, 2, 3 のどれかを入力すると、1倍、2倍、3倍の大きさで画面の中央に顔を描くプログラムを作りなさい。

3.6 メソッドの返り値

メソッドによっては、sfcInput のように、呼び出すと実行結果の値を返してくれます。これをメソッドの返り値(return value) または戻り値と呼びます。このようなメソッドの呼び出しは、定数や変数と同じように式の中に書くことができます。

ボールを投げたときの軌跡を描いてみましょう。まず、sfcTemplate2.java, sfcTemplate2.htmlBall.java,Ball.html にコピーし、プログラム名を Ball に変更します。それから、次のように書きます。
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    void sfcDraw(Graphics g) {
	//ここに自分のプログラムを書く
	for (int t=0; t<=30; t=t+1) { // 0秒から30秒まで
	    g.drawOval(x(t)-5, y(t)-5, 10, 10);  // (x(t),y(t)) を中心とする直径10の円
	}
    }

    int x(int t) { // t 秒後の x 座標の計算
	return t*10;
    }

    int y(int t) { // t 秒後の y 座標の計算
	return 300 - t*30 + t*t;
    }

結果を返さないメソッドを宣言するときは、特別な型 void を使います。void 型のメソッドは、return 文を含まないか、後に式がない return 文を含みます。

3.7 練習問題

キーボードから入力した数値を垂直方向の初速度として、軌跡を描くようにしなさい。なお、初速度は 300 - t*30 + t*t の 30 の部分です。

3.8 宿題

借金の返済をグラフ化するプログラムを書いてみましょう。元金100万円、年利5%、返済期間20年、毎年の返済額を入力して棒グラフにするとします。

  1. 今年の残高と、毎年の返済額と、年利率(%)を引数とし、次の年の残高を返り値とするメソッドはどうなりますか?次の年の残高は
        今年の残高 + 今年の残高 * 年利率 / 100 - 返済額
    
    で計算できます。
  2. Graphics のデータと、何年目かと、その年の残高を引数とし、一本の棒を描くメソッドはどうなりますか?棒を下から描くとすると、上端のY座標は
        300 - 残高 * 300 / 1000000 
    
    で計算できます。なお、棒を描くには、塗り潰した長方形を描くメソッド
    fillRect() を使ってください。
  3. sfcDraw では、返済額を入力し、上のメソッドを20回繰り返して実行します。

実行例

3.9 おまけ1

さらに、年利が 5%, 2%, 0% の場合を、色を変えて重ねて描いてみましょう。残高を100万円に設定し、20回繰り返す部分を独立したメソッドにし、色と年利を変えて呼び出すとよいでしょう。

色を変えるメソッドはこちらを見てください。

実行例

3.10 おまけ2

上の問題では、返済額をいろいろ入力してみないと、うまく年利5%、返済期間20年で返せる額が見つかりません。自動的になるべくピッタリ返せる返済額を計算するメソッドを作ってみましょう。

最初は適当な額(例えば6万円)を返済額として、20年後の残高を計算します。残高が0より大きければ、返済が不足しているということですから、返済額を100円増やしてやり直します。20年後の残高が0以下になるまで、返済額を増やしながら繰り返します。

このような繰り返しは、いつ終わるかがあらかじめ決まっていませんから、forよりも while 文の方が適しています。

     while ( 継続条件 ) {
         繰り返しブロック
     }
なお、for 文で書いたプログラムは、while 文を使って書き直すことができますし、その逆もできます。
[目次] [前回] [次回] [重要語索引]

慶應義塾大学の授業以外での無断利用、複製はご遠慮下さい。
Copyright (c) 2000 慶應義塾大学