目次 | 索引 |
---|---|
今、次のようなプログラムを考えます。
/* 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@Ampere:~/java% java NameTag1 ------------------------- ------------------------- No. ------------------------- Name ------------------------- ------------------------- b00a001@Ampere:~/java%
3行目、4行目、6行目などに、罫線を出力するという、まったく同じ処理が繰り返されています。 これらの処理に名前をつけ、その名前で処理が表せますと、プログラムが読みやすく、かつ書きやすくなります。 メソッドというものを用いますと、そのようなことができます。 なお、メソッドには「インスタンスメソッド」というものと「クラスメソッド」というものがあります。 今日はクラスメソッドのみ扱います。
メソッド ( method ) とは、処理のまとまりに名前をつけたものです。 メソッドを使うためには、プログラムの中でメソッドを定義しなくてはいけません。 メソッドの定義は次のような形をとります。
static void methodname () { statement; ... }
これによって、処理のまとまり
statement
;
...
に
methodname
という名前がつきます。
定義したメソッドを使うには、プログラムに次のような文を書きます。 これを メソッド呼出し ( method call ) とよびます。
methodname();
プログラムの中にメソッド呼出しがありますと、実行の流れは次の図のようになります。
メソッド呼出し
f();
を実行するとき、メソッド
f
の定義の内容を実行し、それが終わったら、メソッド呼出しの次から実行します。
上記のプログラムの場合、次のようになります。
罫線を出力するという処理に、
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*/ }
メソッドには引数を与えることができます。 引数 ( 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@Ampere:~/java% java BindingTest 100 b00a001@Ampere:~/java%
4行目のメソッド呼出し
setZero(x);
を実行しますと、メソッド定義の7行目の変数
n
にデータ100のコピーが格納されます。
コピーを0に置き換えてメソッドを終了しますので、5行目の変数
x
の値は100のままなのです。
メソッドは、まとまった処理をするだけでなく、何らかの計算をして、その値を呼び出し側に返すこともできます。 そのような値を、メソッドの 返り値 ( return value ) とよびます。 返り値は、メソッドの出力データと考えてください。
整数(
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@Ampere:~/java% java MaxTest 200 150 b00a001@Ampere:~/java%
注意:
返り値を持たないメソッドでも
return
文が使えます。
この場合、式を抜いた
return;
という形になります。
メソッドの実行中に
return
文を実行しますと、そこでメソッドの実行を終了します。
メソッドの例として、はじめに
m
の
n
乗を計算するメソッド
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@Ampere:~/java% java PowerTest power(2, 5) is 32 power(5, 2) is 25 power(3, 3) is 27 b00a001@Ampere:~/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@Ampere:~/java% java FactTest fact(4) is 24 fact(5) is 120 fact(6) is 720 b00a001@Ampere:~/java%
最後の例は、塗り潰した長方形を2つ描くアプレットです。
塗り潰した長方形を描くには、
g.fillRect(
...
);
を使うことはすでに説明しました。
ここではこれを用いず、自作のメソッドで長方形を塗り潰すことにします。
アプレットでメソッドを定義する場合、そのメソッドが直線を描いたりするときは、仮引数に
Graphics g
を追加する必要があります。
そして、メソッド呼出しでも、実引数に
g
を追加します。
自作するメソッドの名前は
myFillRect
とします。
引数は、まず
Graphics
の
g
, そして長方形の左上の座標
x
,
y
, 幅
width
および高さ
height
とします。
このメソッドは値を返しませんので、
static void
と指定します。
長方形は、上から順にすきまなく水平線を引いていけば、塗り潰すことができます。
メソッド定義のアルゴリズムは次のようになります。
メソッド呼出しのアルゴリズムは次のようになります。
プログラムは以下のようになります。
/* 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, 150, 50); /* 7*/ myFillRect(g, 100, 100, 50, 50); /* 8*/ } /* 9*/ static void myFillRect (Graphics g, int x, int y, /*10*/ int width, int height) { /*11*/ int i; /*12*/ for (i = 0; i <= height; i++) { /*13*/ g.drawLine(x, y + i, x + width, y + i); /*14*/ } /*15*/ } /*16*/ }
塗り潰した台形を組み合わせることにより、塗り潰した五角形(Pentagon)を描くアプレット(縦横200ピクセル)を作成してください。 組み合わせ方は下図の通りとします。 上の部分は三角形ですが、これは上底の長さが0の台形と考えることにします。
点 | A | B | C | D | E |
---|---|---|---|---|---|
x座標 | 100 | 24 | 53 | 147 | 176 |
y座標 | 20 | 75 | 165 | 165 | 75 |
プログラムは、塗り潰した台形を描くメソッドの定義と、そのメソッド呼出しから構成されます。
メソッドの名前は
fillTrap
とし、引数は
Graphics
の
g
, 台形の左上の座標
x
0
,
y
0
, 上底の長さ
w
0
, 左下の座標
x
1
,
y
1
, および下底の長さ
w
1
とします。
このメソッドは値を返しません。
台形は、すきまなく水平線を引くことによって塗り潰します。 水平線の y 座標が与えられたとき、左端の x 座標とその長さ w は、
x = x 0 +( x 1 − x 0 )×( y − y 0 )/( y 1 − y 0 )
w = w 0 +( w 1 − w 0 )×( y − y 0 )/( y 1 − y 0 )
となることが数学的に導かれますので、この公式を利用します。
メソッド定義のアルゴリズムは次のようにします。
メソッド呼出しのアルゴリズムは次のようにします。
余力のある人は、以下の図表を参考にして、塗り潰した星形を描いてください。 メソッド定義は、五角形のときと同じものを使います。
点 | A | B | C | D | E | F | G | H | I | J | K | L |
---|---|---|---|---|---|---|---|---|---|---|---|---|
x座標 | 100 | 82 | 24 | 71 | 53 | 100 | 147 | 129 | 176 | 118 | 64 | 136 |
y座標 | 20 | 75 | 75 | 109 | 165 | 131 | 165 | 109 | 75 | 75 | 131 | 131 |
今日の演習8に従ってJavaプログラムを作成し、そのプログラムをkonishi@twcu.ac.jpあてにメールで提出してください。 メールには、学生番号、氏名、科目名、授業日(11/14)を明記してください。