[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

情報処理IIIA(Javaプログラミング入門)第8回

目次 索引
8.1 手続きとしてのメソッド
8.1.1 メソッドとは
8.1.2 メソッドの引数
8.2 関数としてのメソッド
8.2.1 メソッドの返り値
8.2.2 メソッドの使用例
8.3 演習8
8.4 レポート課題
値呼出し  返り値  仮引数  関数  実引数  手続き  引数  メソッド  メソッド呼出し 

8.1 手続きとしてのメソッド

8.1.1 メソッドとは

今、次のようなプログラムを考えます。

/*  1*/ class NameTag1 {
/*  2*/     public static void main (String[] args) {
/*  3*/         System.out.println("-------------------------");
/*  4*/         System.out.println("-------------------------");
/*  5*/         System.out.println("No.");
/*  6*/         System.out.println("-------------------------");
/*  7*/         System.out.println("Name");
/*  8*/         System.out.println();
/*  9*/         System.out.println("-------------------------");
/* 10*/         System.out.println("-------------------------");
/* 11*/     }
/* 12*/ }
b00a001@AsiaA1:~/java% java NameTag1
-------------------------
-------------------------
No.
-------------------------
Name

-------------------------
-------------------------
b00a001@AsiaA1:~/java%

3行目、4行目、6行目などに、罫線を出力するという、まったく同じ処理が繰り返されています。 これらの処理に名前をつけ、その名前で処理が表せますと、プログラムが読みやすく、かつ書きやすくなります。 メソッドというものを用いますと、そのようなことができます。 なお、メソッドには「インスタンスメソッド」というものと「クラスメソッド」というものがあります。 今日はクラスメソッドのみ扱います。

メソッドmethod ) とは、処理のまとまりに名前をつけたものです。 メソッドを使うためには、プログラムの中でメソッドを定義しなくてはいけません。 メソッドの定義は次のような形をとります。

static void methodname () {
    statement; ...
}

これによって、処理のまとまり statement ; ...methodname という名前がつきます。

定義したメソッドを使うには、プログラムに次のような文を書きます。 これを メソッド呼出しmethod call ) とよびます。

methodname();

プログラムの中にメソッド呼出しがありますと、実行の流れは次の図のようになります。 メソッド呼出し f(); を実行するとき、メソッド f の定義の内容を実行し、それが終わったら、メソッド呼出しの次から実行します。

Execution flow on a method call
図 8.1  メソッド呼出しにおける実行の流れ

上記のプログラムの場合、次のようになります。 罫線を出力するという処理に、 rule という名前をつけています。 メソッド呼出し rule(); を実行しますと、罫線が出力されます。

/*  1*/ class NameTag2 {
/*  2*/     public static void main (String[] args) {
/*  3*/         rule();
/*  4*/         rule();
/*  5*/         System.out.println("No.");
/*  6*/         rule();
/*  7*/         System.out.println("Name");
/*  8*/         System.out.println();
/*  9*/         rule();
/* 10*/         rule();
/* 11*/     }
/* 12*/     static void rule () {
/* 13*/         System.out.println("-------------------------");
/* 14*/     }
/* 15*/ }

メソッド定義の中では、他のメソッドを使うこともできます。 次の例では、罫線を出力するメソッド rule を使って、二重の罫線を出力するメソッド doubleRule を定義しています。

/*  1*/ class NameTag3 {
/*  2*/     public static void main (String[] args) {
/*  3*/         doubleRule();
/*  4*/         System.out.println("No.");
/*  5*/         rule();
/*  6*/         System.out.println("Name");
/*  7*/         System.out.println();
/*  8*/         doubleRule();
/*  9*/     }
/* 10*/     static void rule () {
/* 11*/         System.out.println("-------------------------");
/* 12*/     }
/* 13*/     static void doubleRule () {
/* 14*/         rule();
/* 15*/         rule();
/* 16*/     }
/* 17*/ }

8.1.2 メソッドの引数

メソッドには引数を与えることができます。 引数argument ) とは、メソッドに対する入力データだと思ってください。 なお、コマンドライン引数はJavaアプリケーションの引数で、アプレット・パラメタはJavaアプレットの引数です。

引数を持つメソッドは次のように定義されます。 argument の部分に、引数を表す変数を書きます。

static void methodname (int argument, ...) {
    statement; ...
}

このようなメソッドを呼び出すには、次のように書きます。 argument の部分に、引数となる式を書きます。

methodname(argument, ...);

メソッド定義の引数を 仮引数formal argument ) とよび、メソッド呼出しの引数を 実引数actual argument ) とよびます。 メソッドは呼び出されますと、仮引数(変数)に実引数(式)の値が代入され、メソッド定義の内容が実行されます。

次の例では、 n 重の罫線を出力するメソッド multiRule を定義しています。 メソッド呼出し multiRule(2); が実行されますと、メソッド定義の仮引数 n に実引数の値2が代入され、罫線の出力を2回繰り返すようにメソッドが実行されます。 なお、メソッド定義の中でも変数が宣言できることに注意してください。 (11行目)

/*  1*/ class NameTag4 {
/*  2*/     public static void main (String[] args) {
/*  3*/         multiRule(2);
/*  4*/         System.out.println("No.");
/*  5*/         multiRule(1);
/*  6*/         System.out.println("Name");
/*  7*/         System.out.println();
/*  8*/         multiRule(2);
/*  9*/     }
/* 10*/     static void multiRule (int n) {
/* 11*/         int i;
/* 12*/         for (i = 0; i < n; i++) {
/* 13*/             System.out.println("-------------------------");
/* 14*/         }
/* 15*/     }
/* 16*/ }

メソッドを呼び出すとき、仮引数には実引数の値が代入されます。 詳しく言いますと、呼出しの際、仮引数の変数が用意され、そこに実引数の値のコピーが格納されます。 このような呼び出し方を、 値呼出しcall by value ) とよびます。

次のプログラムは、引数を0にしようとしてもうまくいかない例です。

/*  1*/ class BindingTest {
/*  2*/     public static void main (String[] args) {
/*  3*/         int x = 100;
/*  4*/         setZero(x);
/*  5*/         System.out.println(x);
/*  6*/     }
/*  7*/     static void setZero (int n) {
/*  8*/         n = 0;
/*  9*/     }
/* 10*/ }
b00a001@AsiaA1:~/java% java BindingTest
100
b00a001@AsiaA1:~/java%

4行目のメソッド呼出し setZero(x); を実行しますと、メソッド定義の7行目の変数 n にデータ100のコピーが格納されます。 コピーを0に置き換えてメソッドを終了しますので、5行目の変数 x の値は100のままなのです。


8.2 関数としてのメソッド

8.2.1 メソッドの返り値

メソッドは、まとまった処理をするだけでなく、何らかの計算をして、その値を呼び出し側に返すこともできます。 そのような値を、メソッドの 返り値return value ) とよびます。 返り値は、メソッドの出力データと考えてください。

一般的なプログラミングの用語では、値を返さないプログラム単位を 手続きprocedure )と呼び、値を返すプログラム単位を 関数function )と呼びます。 Javaでは、手続きも関数もメソッドで実現します。

整数( int 型)を返り値に持つメソッドは、次のように定義されます。

static int methodname (int argument, ...) {
    statement; ...
}

これまでの、返り値を持たないメソッド定義での void の代わりに、 int と書きます。 この定義の中に、少なくとも一つ return 文を書きます。 return 文は次のような形をとり、式 expression の値がこのメソッドの返り値になります。

return expression;

返り値を持つメソッドは、次のような式で呼び出します。

methodname(argument, ...)

式の中にメソッド呼出しがありますと、メソッド定義の内容が実行されます。 そして、その中の return 文が実行されますと、メソッドの実行は終了され、 return 文の式の値が呼び出し側に返されます。

次の例では、二つの数のうち大きい方を返すメソッド max を定義しています。 返り値を持つメソッドは、式として呼び出されることに注意してください。

/*  1*/ class MaxTest {
/*  2*/     public static void main (String[] args) {
/*  3*/         System.out.println(max(100, 200));
/*  4*/         System.out.println(100 + max(20 + 30, 30));
/*  5*/     }
/*  6*/     static int max (int m, int n) {
/*  7*/         if (m > n) {
/*  8*/             return m;
/*  9*/         } else {
/* 10*/             return n;
/* 11*/         }
/* 12*/     }
/* 13*/ }
b00a001@AsiaA1:~/java% java MaxTest
200
150
b00a001@AsiaA1:~/java%

注意: 返り値を持たないメソッドでも return 文が使えます。 この場合、式を抜いた return; という形になります。 メソッドの実行中に return 文を実行しますと、そこでメソッドの実行を終了します。

8.2.2 メソッドの使用例

メソッドの例として、はじめに mn 乗を計算するメソッド power を定義します。 ここで、 n ≧0 と仮定します。

/*  1*/ class PowerTest {
/*  2*/     public static void main (String[] args) {
/*  3*/         System.out.println("power(2, 5) is " + power(2, 5));
/*  4*/         System.out.println("power(5, 2) is " + power(5, 2));
/*  5*/         System.out.println("power(3, 3) is " + power(3, 3));
/*  6*/     }
/*  7*/     static int power (int m, int n) {
/*  8*/         int i, result = 1;
/*  9*/         for (i = 0; i < n; i++) {
/* 10*/             result = result * m;
/* 11*/         }
/* 12*/         return result;
/* 13*/     }
/* 14*/ }
b00a001@AsiaA1:~/java% java PowerTest
power(2, 5) is 32
power(5, 2) is 25
power(3, 3) is 27
b00a001@AsiaA1:~/java%

次の例は、階乗を計算するメソッド fact です。 ここで n の階乗とは、 n ! と表され、

n ! = 1×2×…×( n - 1)× n

と定義されるものです。 ( n ≧0 と仮定しています。)

/*  1*/ class FactTest {
/*  2*/     public static void main (String[] args) {
/*  3*/         System.out.println("fact(4) is " + fact(4));
/*  4*/         System.out.println("fact(5) is " + fact(5));
/*  5*/         System.out.println("fact(6) is " + fact(6));
/*  6*/     }
/*  7*/     static int fact (int n) {
/*  8*/         int i, result = 1;
/*  9*/         for (i = 1; i <= n; i++) {
/* 10*/             result = result * i;
/* 11*/         }
/* 12*/         return result;
/* 13*/     }
/* 14*/ }
b00a001@AsiaA1:~/java% java FactTest
fact(4) is 24
fact(5) is 120
fact(6) is 720
b00a001@AsiaA1:~/java%

最後の例は、塗り潰した正方形を描くアプレットです。

A filled square
図 8.2  塗り潰した正方形

この図は、これまでに何度か描きました。 最初は、 g.fillRect( ... ); を使いました。

/*  1*/ import java.applet.*;
/*  2*/ import java.awt.*;
/*  3*/ 
/*  4*/ public class BlackBox extends Applet {
/*  5*/     public void paint (Graphics g) {
/*  6*/         g.setColor(Color.black);
/*  7*/         g.fillRect(50, 50, 100, 100);
/*  8*/     }
/*  9*/ }

次は、上から順にすきまなく水平線を引いて、塗り潰しました。

/*  1*/ import java.applet.*;
/*  2*/ import java.awt.*;
/*  3*/
/*  4*/ public class FillSquare extends Applet {
/*  5*/     public void paint (Graphics g) {
/*  6*/         int i;
/*  7*/         for (i = 0; i <= 100; i++) {
/*  8*/             g.drawLine(50, 50 + i, 150, 50 + i);
/*  9*/         }
/* 10*/     }
/* 11*/ }

今回は、水平線で塗り潰すことをメソッドにまとめます。 つまり、 g.fillRect( ... ); に相当するメソッドを自作します。

アプレットに関するメソッドを定義する場合、そのメソッドが直線を描いたりするときは、仮引数に Graphics g を追加する必要があります。 そして、メソッド呼出しでも、実引数に g を追加します。

自作するメソッドの名前を myFillRect とします。 引数は、まず Graphics g , そして正方形(長方形)の左上の座標 x , y , 幅 width および高さ height とします。 このメソッドは値を返しませんので、 static void と指定します。

メソッド定義のアルゴリズムは次のようになります。

  1. ループ制御変数 i を宣言する。
  2. 変数 i の値を 0 から height 以下の間増加させながら、以下を繰り返す。{
  3.     座標 ( x , yi ) から右に長さ width の水平線を引く。

メソッド呼出しのアルゴリズムは次のようになります。

  1. 引数を g ,(左上の座標)50, 50,(幅)100,(高さ)100 としてメソッド myFillRect を呼び出す。

プログラムは以下のようになります。

/*  1*/ import java.applet.*;
/*  2*/ import java.awt.*;
/*  3*/
/*  4*/ public class FillRectangle extends Applet {
/*  5*/     public void paint (Graphics g) {
/*  6*/         myFillRect(g, 50, 50, 100, 100);
/*  7*/     }
/*  8*/     static void myFillRect (Graphics g, int x, int y,
/*  9*/                             int width, int height) {
/* 10*/         int i;
/* 11*/         for (i = 0; i <= height; i++) {
/* 12*/             g.drawLine(x, y + i, x + width, y + i);
/* 13*/         }
/* 14*/     }
/* 15*/ }

8.3 演習8

次のような電光掲示板のアプレットを作成してください。

An image of neon sign
図 8.3  電光掲示板のイメージ

一つ一つの電球の描画はメソッド flash によって行います。 引数は、まず Graphics g , そして電球の左上の座標 x , y です。 このメソッドは値を返しませんので、 static void と指定します。

メソッド定義のアルゴリズムは次のようにします。

  1. 左上の座標が ( x +1, y +1) で幅と高さが 18 の正方形に、内接する円を青で塗り潰す。
  2. 左上の座標が ( x +3, y +3) で幅と高さが 12 の正方形に、内接する円を水色で塗り潰す。
  3. 左上の座標が ( x +5, y +5) で幅と高さが 6 の正方形に、内接する円を白で塗り潰す。

メソッド呼出しのアルゴリズムは次のようにします。

  1. 全体を黒で塗り潰す。
  2. 引数を g ,(左上の座標)60, 20 としてメソッド flash を呼び出す。
  3. 引数を g ,(左上の座標)80, 20 としてメソッド flash を呼び出す。
  4. 引数を g ,(左上の座標)100, 20 としてメソッド flash を呼び出す。
  5. 引数を g ,(左上の座標)40, 40 としてメソッド flash を呼び出す。
  6. 引数を g ,(左上の座標)120, 40 としてメソッド flash を呼び出す。
  7. 引数を g ,(左上の座標)40, 60 としてメソッド flash を呼び出す。
  8. 引数を g ,(左上の座標)120, 60 としてメソッド flash を呼び出す。
  9. 引数を g ,(左上の座標)40, 80 としてメソッド flash を呼び出す。
  10. 引数を g ,(左上の座標)120, 80 としてメソッド flash を呼び出す。
  11. 引数を g ,(左上の座標)40, 100 としてメソッド flash を呼び出す。
  12. 引数を g ,(左上の座標)120, 100 としてメソッド flash を呼び出す。
  13. 引数を g ,(左上の座標)40, 120 としてメソッド flash を呼び出す。
  14. 引数を g ,(左上の座標)120, 120 としてメソッド flash を呼び出す。
  15. 引数を g ,(左上の座標)60, 140 としてメソッド flash を呼び出す。
  16. 引数を g ,(左上の座標)80, 140 としてメソッド flash を呼び出す。
  17. 引数を g ,(左上の座標)100, 140 としてメソッド flash を呼び出す。

このアルゴリズムをプログラムにしてください。

余力のある人は、以下の例を参考にして、文字の構成や電球のデザインを他のものにしてください。 文字の構成と電球のデザインを分離することがポイントです。

An image of neon sign
図 8.4  電光掲示板のイメージ

8.4 レポート課題

今日の演習8に従ってJavaプログラムを作成し、そのプログラムをkonishi@twcu.ac.jpあてにメールで提出してください。 メールには、学生番号、氏名、科目名、授業日(11/13)を明記してください。


[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

2003年11月13日更新
konishi@twcu.ac.jp
Copyright (C) 2003 Zenjiro Konishi. All rights reserved.