これまではメインメソッドに全ての処理を書いてきました。
しかし、そのようなプログラムはJavaの本来のプログラムではありません。
本来はメインメソッドは最小限の処理を書き、複数のメソッドと協調して大きな処理を実現します。
ここからは複数のメソッドをあわせて大きな処理をすることを考えます。
一口にメソッドといっても、staticメソッド(スタティックメソッド)とインスタンスメソッドがあります。
まず、staticメソッドを作成してみましょう。
staticメソッドはインスタンス化せずに呼び出せるメソッドでした。
以下のクラスをIDEにコピーして、プログラムを作成しなさい。
(以降の問題演習はこのクラスに追加変更を加えること。途中経過はコメントアウトして残すこと)
次のプログラムコードに、各設問の条件にあうメソッドを追加しなさい。
その後、そのメソッドが正しく動作することを検証するためのプログラムコードをmainメソッドの中に追加しなさい。
public class QXX {
// ここにあなたがstaticメソッドを追加する
public static void main(String[] args) {
// ここに、あなたが追加したstaticメソッドをテストするコードを追加する
}
}
1.引数あり、戻り値あり
以下のstaticメソッドを作成しなさい。
メソッド名:getRectangleArea
引数列: double width, double height
戻り値の型: double
処理の内容: 幅が width、高さが height で表される長方形の面積を返す
ヒント:メインメソッドは以下のようになる。
<結果:実引数として10と10を渡した場合>
100.0 |
2.引数なし、戻り値なし
以下のstaticメソッドを作成しなさい。
メソッド名: printE
引数列:なし
戻り値:なし
処理の内容: 自然対数の底e(≒2.718281828459045)の値を出力する
ヒント:
・自然対数の底eの値は Math クラスのstatic変数 E に格納されている。
・System.out.println(Math.E); で、この値を出力できる。
・メインメソッドは以下のようになる。
<結果>
2.718281828459045 |
3.引数あり、戻り値なし
以下のstaticメソッドを作成しなさい。
メソッド名: sayHello
引数列: String name
戻り値:なし
処理の内容: 引数で渡されたnameに対して挨拶する
ヒント:メインメソッドは以下のようになる。
<結果>
Hello! imai san. |
4.引数あり、戻り値なし
以下のstaticメソッドを作成しなさい。
メソッド名: printSquareArea
引数列: double oneSide
戻り値:なし
処理の内容: 引数で渡された値を一辺とする正方形の面積を出力する
<結果:1辺の長さを3.14で渡した場合>
9.8596 |
5.引数が複数、戻り値なし
以下のstaticメソッドを作成しなさい。
メソッド名: printMessage
引数列: String message, int count
戻り値:なし
処理の内容: 文字列 message を、count の回数だけ繰り返し出力する
<結果>
printMessage("Hello", 5); として呼び出した場合
Hello Hello Hello Hello Hello |
6.引数なし、戻り値あり
以下のstaticメソッドを作成しなさい。
メソッド名: getMessage
引数列:なし
戻り値の型: String
処理の内容: "I LOVE YOUxxx" という文字列を返す
<結果>
System.out.println(getMessage());として呼び出した場合
I LOVE YOUxxx |
7.実引数がメソッド
mainメソッドの中で5のprintMessageメソッドの第一引数を6のgetMessageメソッドにして実行してみる。
<結果>
printMessage(getMessage(), 5);として呼び出した場合
I LOVE YOUxxx I LOVE YOUxxx I LOVE YOUxxx I LOVE YOUxxx I LOVE YOUxxx |
8.戻り値の型がboolean
メソッド名: isEvenNumber
引数列: int value
戻り値の型: boolean
処理の内容: 引数で渡された値が偶数の場合は true、そうでない場合は false を返す。
<結果>
System.out.println(isEvenNumber(255));として呼び出した場合
false |
9.引数が複数、戻り値あり
以下のstaticメソッドを作成しなさい。
メソッド名:getMinValue
引数列:double a, double b
戻り値の型:double
処理の内容: 引数で受け取る2の値のうち、小さい方の値を返す(三項演算子を使うこと)
<結果>
System.out.println(getMinValue(3, 4));として呼び出した場合
3.0 |
10.引数が配列
以下のstaticメソッドを作成しなさい。
メソッド名: getAverage
引数列:double[] array
戻り値の型:double
処理の内容: 引数で受け取る配列の要素の平均値を返す
<結果>
System.out.println(getAverage(new double[]{1, 2, 3, 4, 5, 6, 7, 8, 9}));として呼び出した場合※
※変数は参照を入れる箱に過ぎないので、配列を作るだけであれば上記のように変数を用意せず、いきなりnewする書き方ができることも理解しておいてください。
5.0 |
11.戻り値が配列
以下のstaticメソッドを作成しなさい。
メソッド名: getRandomNumbers
引数列:int num
※乱数の個数
戻り値の型:int[]
処理の内容: 引数で受け取った数の乱数が入った配列(の参照)を返す。ただし、乱数は0~10の範囲とする。
<結果の例:乱数を10個作る>
int[] array = getRandomNumbers(10); for (int i : array) { System.out.print(i + " "); } |
で呼び出したとき
10 0 7 3 6 1 4 4 5 2 |
12.メソッドからメソッドを呼ぶ
以下のstaticメソッドを作成しなさい。
メソッド名: sayHellos
引数列: String name, int count
戻り値:なし
処理の内容: 3で作成したsayHelloメソッドを、count の回数だけ繰り返し呼ぶ。
<結果>
sayHellos("imai", 5); として呼び出した場合
Hello! imai san. Hello! imai san. Hello! imai san. Hello! imai san. Hello! imai san. |
13.メソッドチェーン
メソッドチェーンを使った問題です。
6のgetMessage()を使って得られた文字列の文字数をlength()メソッドで取得し、コンソールに出力する処理をメインメソッドの中に1行で記述しなさい。
<結果>
13 |
14.再帰を使って階乗計算をする
以下のstaticメソッドを作成して階乗計算(※)をしなさい。
※階乗計算とは
非負整数 n の階乗 n ! は、1 から n までのすべての整数の積のこと。
例:6!=6×5×4×3×2×1=720
メソッド名: fact
引数列:int n
※ただし、nは正
戻り値の型:int
処理の内容: もしも、n が0なら1を返す。そうでなければ、n * fact(n - 1) を返す。
<結果>
System.out.println(fact(6));として呼び出した場合
720 |
15.再帰を使ってフィボナッチ数列を表示する
staticメソッドを作成して以下の出力結果にあるフィボナッチ数列(※)を表示しなさい。
※フィボナッチ数列とは
例:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,…
のように最初の二項は 0, 1 であり、以後どの項もその直前の2つの項の和となっている数列のこと。
その不思議な性質についてはリンクの動画を参照の事。
メソッド名: fib
引数列:int n
※ただし、nは0または正
戻り値の型:int
処理の内容: もしも、n が0または1なら1を返す。そうでなければ、fib(n - 1) + fib(n - 2) を返す。
<結果>
for (int i = 0; i <= 6; i++) { System.out.println("fib(" + i + ") =" + fib(i)); } |
として呼び出した場合
fib(0) =1 fib(1) =1 fib(2) =2 fib(3) =3 fib(4) =5 fib(5) =8 fib(6) =13 |
※なお、階乗計算やフィボナッチ数列を表示するには単純な繰り返しで十分です。再帰を使うとパフォーマンスはよくありません。再帰を使うべきは、例えばこの後出てくるハノイの塔等の場合です。
16.エラーの見方
以下のソースコードでは、4つのメソッドmain、A、B、Cがあり、mainからAを、AからBを、BからCを呼んでいる。
このプログラムを実行して、コンソールに表示されるエラーを読み解き、そこからエラーが出た際に我々はどこを見るべきかという一般原則を導き出しなさい。
package p08;
public class Q20 {
private static void methodA(int num1, int num2) {
methodB(num1, num2);
}
private static void methodB(int num1, int num2) {
methodC(num1, num2);
}
private static void methodC(int num1, int num2) {
System.out.println(num1 / num2);
}
public static void main(String[] args) {
methodA(5, 0);
}
}
17.メソッドの切り出し
あなたは、テスト結果を管理するJavaプログラムを作成した。
プログラムの目的は合計点数と平均点数、平均年齢を求めることである。
あなたが最初に書いたソースコードは以下の通りである。
ところが、処理が重複して書かれていることに気づいた。
合計を求める処理をメソッドに切り出しなさい。
なお、必要に応じてメソッド名やローカル変数名を自由につけること。
package p08;
public class Q17 {
public static void main(String[] args) {
int[] scores = {60, 53, 5, 68, 82, 70, 83, 12, 3, 72, 38, 68, 92, 15, 92, 48, 13, 14, 80};
int[] ages = {22, 29, 28, 29, 26, 23, 30, 23, 27, 23, 28, 28, 26, 27, 26, 28, 30, 25, 22};
int sum = 0;
double avg = 0;
for (int i = 0; i < scores.length; i++) {
sum += scores[i];
}
System.out.println("合計点数:" + sum);
System.out.println("平均点数:" + (double)sum / scores.length);
for (int i = 0; i < ages.length; i++) {
avg += ages[i];
}
avg = avg / ages.length;
System.out.println("平均年齢:" + avg);
}
}
合計点数:968 平均点数:50.94736842105263 平均年齢:26.31578947368421 |
<結果:変更前と同じ>
<メソッド切り出し後のソースコードの一部>
package p08;
public class Q17ans {
public static void main(String[] args) {
int[] scores = {60, 53, 5, 68, 82, 70, 83, 12, 3, 72, 38, 68, 92, 15, 92, 48, 13, 14, 80};
int[] ages = {22, 29, 28, 29, 26, 23, 30, 23, 27, 23, 28, 28, 26, 27, 26, 28, 30, 25, 22};
int sum = 0;
double avg = 0;
System.out.println("合計点数:" + sum(scores));
System.out.println("平均点数:" + sum(scores) / scores.length);
System.out.println("平均年齢:" + sum(ages)/ages.length);
}
//ここに切り出したsumメソッドを書く
}
18.メソッドのオーバーロード
以下のプログラムは成績の合計と体重の合計を求めるプログラムである。
成績は整数で、体重は実数で与えられるものとする。
体重の合計を正しく求められるようにsumメソッドをオーバーロードしなさい。
ただし、体重の合計にあたっては、合計値の小数点以下を切り捨てるものとする。
package p08;
public class Q18 {
public static void main(String[] args) {
int[] iscores = {60, 53, 5, 68, 82, 70, 83, 12, 3, 72, 38, 68, 92, 15, 92, 48, 13, 14, 80};
double[] dweights = {54.7, 86.1, 82.5, 65.4, 98.9, 75.2, 81.9, 58.9, 94.4, 91.9, 90.9, 88.3, 76.8, 57.3, 68.1, 69.7, 58.6, 99.5, 93.9};
int sumI = sum(iscores);
int sumD = sum(dweights);
System.out.println("スコア合計:" + sumI);
System.out.println("体重合計:" + sumD);
}
public static int sum(int[] num) {
int sum = 0;
for (int i = 0; i < num.length; i++) {
sum += num[i];
}
return sum;
}
//ここにオーバーロードしたsumメソッドを書く
}
<結果>
スコア合計:968 体重合計:1492 |
19.ローカル変数のスコープ
以下のプログラムを実行したら何が出力されるか?また、それはなぜか説明しなさい。
package p08;
public class Q19 {
public static void main(String[] args) {
int num = 1;
System.out.println(num);
local();
System.out.println(num);
}
static void local() {
int num = 2;
System.out.println(num);
}
}
20.数当てゲーム再び
卒業課題で作成した数あてゲームが以下の通りだったとします。
このプログラムはmainメソッドに全ての処理が書かれています。
package graduation1;
import java.util.Random;
import java.util.Scanner;
public class Q04 {
public static void main(String[] args) {
System.out.println("レベルを選んで下さい (1)0~9 (2)0~99 (3)0~999 ");
Scanner scanner = new Scanner(System.in);
Random random = new Random();
int answer = 0;
int level = 0;
while (level < 1 || 3 < level) {
level = scanner.nextInt();
switch (level) {
case 1:
answer = random.nextInt(9) + 1;
break;
case 2:
answer = random.nextInt(99) + 1;
break;
case 3:
answer = random.nextInt(999) + 1;
break;
default:
System.out.println("もう一度レベルを選んでください (1)0~9 (2)0~99 (3)0~999 ");
}
}
System.out.println("秘密の答え:" + answer);
System.out.println("5回以内に数を当ててね。3回以内ならすごいことだよ。");
long start = System.currentTimeMillis();
int i;
int[] history = {-1, -1, -1, -1, -1};
for (i = 0; i < 5; i++) {
System.out.println("キーボードから数値を入力してください");
Scanner sc2 = new Scanner(System.in);
int inputted = sc2.nextInt();
history[i] = inputted;
if (answer == inputted) {
break;
} else if (answer > inputted) {
System.out.println("もっと大きいよ");
} else {
System.out.println("もっと小さいよ");
}
}
if (i < 3) {
System.out.println("大あたり!すごいことだよ!");
} else if (i < 5) {
System.out.println("あたり。まあまあすごいよ。");
} else {
System.out.println("5回以内に答えられなかったのでゲーム終了");
}
long end = System.currentTimeMillis();
System.out.println((end - start) / 1000 + "秒かかったよ");
System.out.println("次回のために履歴を表示するので参考にしてね");
for (int j = 0; j <= i; j++) {
System.out.print(history[j] + "→");
}
System.out.print("終了!");
}
}
このとき、スタティックメソッドを使ったプログラムを作成したい。
以下の書きかけのプログラムと整合するようにスタティックメソッドを作成しなさい。
package p08;
import java.util.Random;
import java.util.Scanner;
public class Q21StaticMethod {
public static void main(String[] args) {
int answer = getAnswer();
long start = System.currentTimeMillis();
int i = 0;
int[] history = {-1, -1, -1, -1, -1};
i = checkTheAnswer(i, history, answer);
long end = System.currentTimeMillis();
System.out.println((end - start) / 1000 + "秒かかったよ");
showHistory(i, history);
}
//スタティックメソッドを作成しなさい。
}
21.再帰を使ってハノイの塔の円盤の操作を表示する
以下のstaticメソッドを作成してハノイの塔(※)の円盤の操作を表示しなさい。
※ハノイの塔とは(Wikipedia参照)
パズルの一種。
以下のルールに従ってすべての円盤を右端の杭に移動させられれば完成。
- 3本の杭と、中央に穴の開いた大きさの異なる複数の円盤から構成される。
- 最初はすべての円盤が左端の杭に小さいものが上になるように順に積み重ねられている。
- 円盤を一回に一枚ずつどれかの杭に移動させることができるが、小さな円盤の上に大きな円盤を乗せることはできない。
メソッド名: hanoi
引数列:char x, char y, char z, int n
※ただし、x,y,zは杭の名前、nは円盤の枚数
戻り値の型:void
処理の内容: 各自で考えること。
アウトプット例:hanoi('A', 'B', 'C', 3)
From A to C From A to B From C to B From A to C From B to A From B to C From A to C |
※伝説では64枚の円盤の移し替えが終わったときに、世界は崩壊し終焉を迎えるそうです。試してみてください。
そして、この例のように延々と処理が終わらない場合の途中終了の方法も講師から聞いておきましょう。
22.オリジナル問題作成
将来の後輩のために良い問題が出来たら教えてください。