|
|
メソッドの利用 |
H.Kamifuji . |
クラスの主要な要素の一つがメソッドです。メソッドはクラスが持つ機能を定義するためのものです。 クラスを使ったオブジェクト指向のプログラミングを行う場合のメソッドの使い方についてはまた別のところで詳しく確認していきますが、ここではメソッドを関数のように使用する方法を使ってメソッドの基本的な利用方法を一通り確認していきます。 当ページでは、Linux CentOS7 の Gnome で動作テストしています。 現在(2021/08)では、JDK-16.0.2 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2021/11)では、JDK-17.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2023/04)では、JDK-20.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2024/10)では、JDK-23 にアップされています。一部、上位互換について、見直しを行っていきます。 |
|
まずはどのような場合にメソッドが使われるのかを確認していきます。(繰り返しになりますが、クラスの機能を実現するためのメソッドの使い方ではなく、ここではメソッドを関数のように使用する場合で考えます)。 次の例を見て下さい。 public static void main(String args[]){ int eigo = 78; int suugaku = 90; System.out.print("英語の試験結果は"); if (eigo > 80){ System.out.println("合格です"); }else{ System.out.println("不合格です"); } /* 何か別の処理1 */ /* 何か別の処理2 */ System.out.print("数学の試験結果は"); if (suugaku > 80){ System.out.println("合格です"); }else{ System.out.println("不合格です"); } }if文が2回使われていますが条件式の中で使われている変数以外は同じです。上記では2回だけですがこれが3回も4回も同じような処理が記述されていくと無駄に長いプログラムとなってしまいます。 f文が続けて記述されているのであれば配列と繰り返し処理を使って次のように記述することもできます。 public static void main(String args[]){ int seiseki[] = {78, 90}; String kyoka[] = {"英語", "数学"}; for (int i = 0; i < 2; i++){ System.out.print(kyoka[i] + "の試験結果は"); if (seiseki[i] > 80){ System.out.println("合格です"); }else{ System.out.println("不合格です"); } } }ただ、同じような処理を行う複数の文が、プログラムの中で離れたところに記述されていた場合はこの方法は使えません。このような時にはメソッドを使うと便利です。 メソッドは複数の処理をまとめたものです。プログラムの中からメソッドを呼び出すと、そのメソッドで記述された処理が実行されます。先ほどの例をメソッドを使って書き直すと次のようになります。 public static void main(String args[]){ int eigo = 78; int suugaku = 90; check("英語", eigo); /* 何か別の処理1 */ /* 何か別の処理2 */ check("数学", suugaku); } private static void check(String kyoka, int seiseki){ System.out.print(kyoka + "の試験結果は"); if (seiseki > 80){ System.out.println("合格です"); }else{ System.out.println("不合格です"); } }「check」という名前のメソッドを一つ用意しました。このメソッドにはif文を使った画面出力の処理が記述されています。プログラム本体からは必要な時にこのメソッドを呼び出すと、メソッド内に記述された一連の処理が実行されることになります。 このようにメソッドを使うことで何度も実行される一連の処理をひとまとめにしておき、必要に応じて呼び出して実行させることができるようになります。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample1_1{ public static void main(String args[]){ int eigo = 78; int suugaku = 90; int kokugo = 68; check("英語", eigo); check("数学", suugaku); check("国語", kokugo); } private static void check(String kyoka, int seiseki){ System.out.print(kyoka + "の試験結果は"); if (seiseki > 80){ System.out.println("合格です"); }else{ System.out.println("不合格です"); } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Method]$ java JSample1_1 英語の試験結果は不合格です 数学の試験結果は合格です 国語の試験結果は不合格です [xxxxxxxx@dddddddddd Method]$ |
それではメソッドを定義する方法を確認します。メソッドにはインスタンスメソッドとクラスメソッドと呼ばれるものがあり、ここではクラスメソッドをについて利用方法を確認していきます。ただどちらも書式同じで次のようになります。 [修飾子] 戻り値のデータ型 メソッド名(引数1, 引数2, ....){ }例外と呼ばれるものを使う場合には少し違った書式となりますが、例外については別のページにて詳しく解説します。 修飾子はメソッドだけではなくフィールドやクラスにも付けるもので、そのメソッドがどこからアクセス可能なのかを示すアクセス修飾子と呼ばれるものと、その他の修飾子が存在します。詳しくは別のところで説明しますので、しばらく修飾子としては「private static」を付けると考えておいて下さい。 戻り値のデータ型はメソッドが呼び出された時に値を一つだけ呼び出し元に返すことができます。その返す値のデータ型を指定します。何も値を返さない場合はvoid型を指定することになっていますので、取り合えず「void」を記述して下さい。 定義するメソッドには名前をつける必要があります。メソッド名は変数名と同じく識別子を使います。詳しくは「変数名のつけ方(識別子)」を参照して下さい。 メソッドの呼び出し元からメソッドに対して値を渡したい場合に引数を利用します。戻り値は一つだけでしたが、引数は複数個指定することができます。その場合はカンマ(,)で区切って記述していきます。引数が必要無い場合は何も記述する必要はありません。引数についても詳しくは別のページで解説します。 以上をふまえ、メソッドは次のような構成となります。 private static void test(){ /* メソッド内で実行する処理 */ }メソッドが呼び出された時に実行する処理を「{」から「}」のブロックの間に記述します。 メソッドの呼び出しメソッドを定義したらプログラムの中から呼び出すことができます。メソッドの種類によって呼び出し方が実際は異なるのですが、現在使い方を確認しているメソッドの場合は次のように呼び出してください。変数 = メソッド名(値1, 値2, ....);定義されているメソッド名を指定して呼び出します。メソッドに値を渡す場合には括弧の中にカンマ(,)で区切って記述して下さい。値を渡す必要が無い場合は括弧の中は空で結構です(括弧は必要です)。 メソッドで戻り値が設定されている場合は、メソッド呼び出しそのものが戻り値となりますので、変数などに対して代入することができます。 例えば「test」というメソッドを呼び出し、引数も戻り値も無い場合には次のように記述します。 class TestClass{ public static void main(String args[]){ System.out.println("こんにちは"); test(); System.out.println("さようなら"); } private static void test(){ System.out.println("お元気ですか"); } }この時、処理の流れは次のようになります。 プログラム実行開始 mainメソッド内の最初の文から実行される "こんにちは"が画面に出力される testメソッドが呼び出される testメソッドの最初の文から実行される "お元気ですか"が画面に出力される testメソッドのブロックの最後まで達する testメソッドを呼び出した次の文から実行される "さようなら"が画面に出力される mainメソッドのブロックの最後まで達する プログラム終了このようにメソッドを呼び出す文が実行された時点で、処理はメソッドの先頭の文へ移ることになります。そしてメソッド内の処理が順に実行され最後まで達するとメソッドを呼び出した文の次の文から再度実行されていくことになります。 なおメソッドの呼び出しはmainメソッドの中からも行えますし、メソッドの中からさらに他のメソッドを呼び出すこともできます。 メソッドの記述位置メソッドはクラスの中に記述します。プログラムが実行される時に最初に呼び出されるメソッドであるmainメソッドがクラスの中に既に記述されているはずですが、新しく定義するメソッドもクラスの「{」から「}」の中に記述します。この時、メソッドが記述される順番は関係ありません。例えば先ほどのサンプルを次のように記述してもまったく同じように動作します。 class TestClass{ private static void test(){ System.out.println("お元気ですか"); } public static void main(String args[]){ System.out.println("こんにちは"); test(); System.out.println("さようなら"); } }クラスの中でどの位置にmainメソッドが記述されていても最初に呼び出されるメソッドはmainメソッドであり、他のメソッドは明示的に呼び出されない限り実行されることはありません。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample2_1{ public static void main(String args[]){ hello(); bye(); hellobye(); } private static void hello(){ System.out.println("こんにちは。"); } private static void bye(){ System.out.println("さようなら。"); } private static void hellobye(){ hello(); bye(); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Method]$ java JSample2_1 こんにちは。 さようなら。 こんにちは。 さようなら。 [xxxxxxxx@dddddddddd Method]$今回は3つのメソッドを定義して順に呼び出しています。3つ目のメソッドでは他の2つのメソッドを呼び出しています。 |
メソッドを呼び出す時に呼び出し元から値をメソッドに渡すことができます。まずどのような場合に使うのかを確認してみます。次の例を見て下さい。 public static void main(String args[]){ int num1, num2; num1 = 10; num2 = 8; System.out.println("num1 = " + num1 + ",num2 = " + num2); System.out.println("num1 + num2 = " + (num1 + num2)); System.out.println("num1 - num2 = " + (num1 - num2)); System.out.println("num1 * num2 = " + (num1 * num2)); System.out.println("num1 / num2 = " + (num1 / num2)); num1 = 23; num2 = 7; System.out.println("num1 = " + num1 + ",num2 = " + num2); System.out.println("num1 + num2 = " + (num1 + num2)); System.out.println("num1 - num2 = " + (num1 - num2)); System.out.println("num1 * num2 = " + (num1 * num2)); System.out.println("num1 / num2 = " + (num1 / num2)); }この例では2つの値を加算したり乗算したりした結果を表示するものです。繰り返し利用できるように計算して画面に出力する部分をメソッドとして分けてみます。 public static void main(String args[]) { int num1, num2; num1 = 10; num2 = 8; keisan(); num1 = 23; num2 = 7; keisan(); } private static void keisan(){ System.out.println("num1 = " + num1 + ",num2 = " + num2); System.out.println("num1 + num2 = " + (num1 + num2)); System.out.println("num1 - num2 = " + (num1 - num2)); System.out.println("num1 * num2 = " + (num1 * num2)); System.out.println("num1 / num2 = " + (num1 / num2)); }2つの変数に値を設定してからkeisanメソッドを呼び出しています。ただこのサンプルはコンパイルした時点でエラーとなります。原因はブロック内で宣言された変数はブロックの外では利用できないためです。 mainメソッドのブロック内で宣言された変数「num1」と変数「num2」は、mainメソッドのブロックの外であるkeisanメソッドのブロックの中では使うことができません。その為、keisanメソッド内で使われている変数「num1」や変数「num2」が宣言されていない変数を使っているというエラーが発生してしまいます。 このような時に引数を使います。引数を使うことでメソッドを呼び出すたびに任意の値をメソッドに渡す事ができます。 引数があるメソッドの呼び出し方引数があるメソッドの基本的な書式は次のようになります。public static void main(String args[]){ メソッド名(値1, ...); } 修飾子 戻り値の型 メソッド名(データ型 変数名1, ...){ /* メソッド内で実行する処理 */ }メソッドを呼び出す時にメソッドに渡したい値を括弧の間に記述します。複数の値を渡す場合はカンマ(,)で区切り続けて記述します。 メソッド側では渡されてきた値を格納するために変数をメソッド名の後の括弧の中に記述します。この変数のことを引数と呼びます。引数は渡されてくる値の数だけ記述する必要があり、渡されてきる値と同じデータ型を使って宣言されている必要があります。 次の例を見てください。 public static void main(String args[]){ test(16, 'A', 7); test(9, 'd', 24); } private static void test(int n1, char a, int n2){ System.out.println("n1 = " + n1); }メソッドを呼び出す時に3つの値を指定しています。メソッド側では3つの値が渡されてくる為、引数も3つ記述しています。メソッドから渡されてくる値は、記述された順に引数に代入されていきます。この時の処理の流れは次のようなものだと考えて下さい。 test(16, 'A', 7); // testメソッドを呼び出し、3つの値を渡す --- ここからメソッド内の処理 --- int n1 = 16; // 渡されてきた値を引数に順番に代入 char a = 'A'; int n2 = 7; System.out.println("n1 = " + n1); --- ここまでメソッド内の処理 --- test(9, 'd', 24); // testメソッドを呼び出し、3つの値を渡す --- ここからメソッド内の処理 --- int n1 = 9; // 渡されてきた値を引数に順番に代入 char a = 'd'; int n2 = 24; System.out.println("n1 = " + n1); --- ここまでメソッド内の処理 ---メソッドが呼び出されるたびに、その時指定された値がメソッドの引数に代入されます。引数で記述された変数はメソッド内で使用することができますので値を取り出して画面出力を行ったり演算したりすることができます。 注意すべき点は呼び出し元の変数の値が呼び出し先のメソッド内で利用できなかったように、呼び出したメソッド内で使用した変数の値も呼び出し元のメソッドの中では使用できないことです。もしメソッドから何らかの値を呼び出し元に返したい場合には戻り値を使います。戻り値は後のページで解説します。 では一番最初のサンプルを引数があるメソッドを使って正しいプログラムに変更してみます。 public static void main(String args[]){ int num1, num2; num1 = 10; num2 = 8; keisan(num1, num2); num1 = 23; num2 = 7; keisan(num1, num2); } private static void keisan(int n1, int n2){ System.out.println("num1 = " + n1 + ",num2 = " + n2); System.out.println("num1 + num2 = " + (n1 + n2)); System.out.println("num1 - num2 = " + (n1 - n2)); System.out.println("num1 * num2 = " + (n1 * n2)); System.out.println("num1 / num2 = " + (n1 / n2)); }引数を使うことでメソッドを呼び出すたびに異なった値を処理できるようなメソッドを定義することができます。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample3_1{ public static void main(String args[]){ int num1, num2; num1 = 10; num2 = 8; keisan(num1, num2); num1 = 23; keisan(num1, 7); keisan(15, 22); } private static void keisan(int n1, int n2){ System.out.println("num1 = " + n1 + ",num2 = " + n2); System.out.println("num1 + num2 = " + (n1 + n2)); System.out.println("num1 - num2 = " + (n1 - n2)); } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Method]$ java JSample3_1 num1 = 10,num2 = 8 num1 + num2 = 18 num1 - num2 = 2 num1 = 23,num2 = 7 num1 + num2 = 30 num1 - num2 = 16 num1 = 15,num2 = 22 num1 + num2 = 37 num1 - num2 = -7 [xxxxxxxx@dddddddddd Method]$ |
メソッドに渡す値が基本データ型であった場合には、値がコピーされて値そのものが引数に代入されます。考え方としては基本データ型の値を他の変数に代入する場合と同じです。 public static void main(String args[]){ test(10); } private static void test(int num){ System.out.println(num); }基本データ型だけではなくクラスから作成したオブジェクトや配列もメソッドに渡すことができます。 「参照型の変数の考え方」などでも記載したとおり、配列などは実際の値などが格納する場所の位置だけを管理しています。その為、メソッドを呼び出す時に配列を指定した場合には、引数には配列が確保している場所の位置が代入されることになります。つまりメソッドの呼び出し側の配列とメソッド側で引数に代入された配列はまったく同じ場所の位置を管理していることになります。 public static void main(String args[]){ int num[] = {10, 4}; test(num); } private static void test(int num[]){ System.out.println(num[0]); System.out.println(num[1]); }よってメソッド側で配列の要素に格納されている値を変更すると、メソッド呼び出し側の配列の同じ要素に格納されている値を変更されることになります。 public static void main(String args[]){ int num = 8; int array[] = {10, 4}; System.out.println(num); System.out.println(array[0]); test(num, array); System.out.println(num); System.out.println(array[0]); } private static void test(int num, int array[]){ num = 5; array[0] = 12; }上記の場合、基本データ型の変数である「num」は値がコピーされて引数に代入されるだけなので、メソッド側で変数の値を変更しても呼び出し元の変数の値には何も影響しません。それに対して配列変数の「array」は配列の場所の位置が引数に代入されるので、メソッド側で配列の要素の値を変更すると呼び出し元の配列の要素の値も変更されます。(実際の結果は後のサンプルでご確認下さい)。 Stringクラスのオブジェクトの場合文字列を引数に渡す場合、文字列はStringクラスのオブジェクトですので配列と同じようにオブジェクトの位置だけが渡されますが、あまり意識することなく基本データ型のように扱うことができます。次の例を見てください。public static void main(String args[]){ String str = "abc"; test(str); } private static void test(String str){ str = "def"; }Stringクラスのオブジェクトをメソッドに渡した場合、メソッド側の引数には同じオブジェクトの位置が渡されるのは配列と同じですが、文字列変数に新しい文字列を代入するとまったく別の場所にオブジェクトが新しく作成され、その新しい場所の位置がメソッド内の変数に代入されます。その為、元の場所には元の文字列が格納されたままなのでメソッド呼び出し元の文字列には何も影響を与えません。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample4_1{ public static void main(String args[]){ int num = 8; int array[] = {10, 4}; System.out.println("num = " + num); System.out.println("array[0] = " + array[0]); henkou(num, array); System.out.println("num = " + num); System.out.println("array[0] = " + array[0]); } private static void henkou(int num, int array[]){ num = 5; array[0] = 12; } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Method]$ java JSample4_1 num = 8 array[0] = 10 num = 8 array[0] = 12 [xxxxxxxx@dddddddddd Method]$メソッド側で配列の要素を変更すると、呼び出し元の配列にも影響が出ていることが確認できます。 |
メソッドを呼び出す時には引数を使って呼び出し元からメソッドへ値を渡すことができましたが、今度はメソッド内の処理が終了してメソッド呼び出し元へ処理が戻る時に、呼び出し元へ何らかの値を返す方法を確認します。 メソッドから呼び出し元へ返す値を戻り値といいます。戻り値がある場合の書式は次のとおりです。 public static void main(String args[]){ 戻り値のデータ型 変数 = メソッド名(); } 修飾子 戻り値のデータ型 メソッド名(){ /* メソッド内で実行する処理 */ return 戻り値; }※上記では引数に関係する部分は省略しています。 戻り値としてメソッド呼び出し元に値を返す場合、まずメソッドの定義の時にメソッド名の前に戻り値のデータ型を記述します。例えばintなどの基本データ型やStringなどのクラス名を記述します。戻り値を返さない場合にはデータ型としてvoidを記述します。 戻り値がint型の場合: private static int test(){ /* メソッド内で実行する処理 */ }戻り値を返さない場合: private static void test(){ /* メソッド内で実行する処理 */ } return文次に戻り値の指定方法です。戻り値ははreturn文を使って記述します。return文の書式は次のとおりです。return; return 式;return文が実行された時点でメソッドを終了し呼び出し元へ処理が帰ります。return文はメソッド内の任意の位置に記述できますが、return文が実行されるとそれ以降にメソッド内に書かれた処理は実行されませんので注意して下さい。 そして戻り値としてメソッドの呼び出し元に値を返す場合は、return文の後に式として戻り値を記述します。式は単に値や変数を記述した場合にはその値が、計算式などを記述した場合にはその式を評価した結果が戻り値として呼び出し元に返されます。 return 10; /* 戻り値は10 */ return 4 * 5; /* 戻り値は20 */戻り値としてreturn文の後に指定する値のデータ型はメソッド名の前に記述したデータ型である必要があります。またreturn文で指定できる値は一つだけなので戻り値として呼び出し元に返すことができる値も一つだけです。 戻された値の処理戻り値として値が呼び出し元に返されると、メソッドを呼び出した文そのものが戻り値として評価されます。よって、出力したり変数に代入したりすることができます。public static void main(String args[]){ /* 戻り値を直接出力した場合 */ System.out.println(test()); /* 戻り値を変数に代入した場合 */ int num = test(); } private static int test(){ return 10; }メソッドに戻り値のデータ型としてvoid以外を指定しているにも関わらずreturn文を使って戻り値を返さなかった場合もコンパイルエラーとなりますが、返された戻り値をメソッド呼び出し側で利用しなくても構いません。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample5_1{ public static void main(String args[]){ int kekka; kekka = bai(9); System.out.println(kekka); kekka = bai(5); System.out.println(kekka); } private static int bai(int n){ return n * 2; } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Method]$ java JSample5_1 18 10 [xxxxxxxx@dddddddddd Method]$ 今回のサンプルではメソッドに渡された値をメソッド内で2倍し、その結果を呼び出し元に返しています。 ではもう一つ簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample5_2{ public static void main(String args[]){ int num; String kekka; num = 9; kekka = hantei(num); System.out.println(num + "は" + kekka); num = 6; kekka = hantei(num); System.out.println(num + "は" + kekka); } private static String hantei(int n){ if (n % 2 == 0){ return "偶数"; }else{ return "奇数"; } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Method]$ java JSample5_2 9は奇数 6は偶数 [xxxxxxxx@dddddddddd Method]$今回はメソッド内で条件分岐を行い、戻り値で返す値を二通り記述しています。このようにreturn文はメソッド内で複数記述しても構いません。ただ、いずれかのreturn文が実行されるとその時点でメソッドを終了するのでreturn文が実行されるのは一つだけです。 |
戻り値は基本データ型の値だけではなくクラスオブジェクトや配列を返すこともできます。戻り値に指定できる値は一つだけですが、戻り値に複数の要素を持つ配列を指定すれば結果的に複数の値を呼び出し元に返すことも可能です。 次の例を見てください。 public static void main(String args[]){ int data[]; data = test(); System.out.println(data[0]); System.out.println(data[1]); } private static int[] test(){ int data[] = new int[2]; data[0] = 10; data[1] = 19; return data; }この例ではメソッド内で新規に配列を作成し、配列の要素に値を代入してから戻り値として呼び出し元に返しています。 戻り値として指定した変数には配列の場所の位置が格納されています。呼び出し元には配列の位置が返されてきますので、それを代入した配列はメソッドで定義した配列と同じ位置を指し示すことになり、呼び出し元からも配列の要素を取り出すことができます。 Javaの配列では各要素には同じデータ型の値しか格納することができませんが、複数の値を複数の要素に格納した配列を戻り値として呼び出し元に返すことで複数の値を返すことができます。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample6_1{ public static void main(String args[]){ int data[]; data = init(); System.out.println(data[0]); System.out.println(data[1]); } private static int[] init(){ int data[] = new int[2]; data[0] = 10; data[1] = 19; return data; } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Method]$ java JSample6_1 10 19 [xxxxxxxx@dddddddddd Method]$ |
メソッドから呼び出し元に値を返す場合には、return文を使って戻り値を指定しますが、return文は戻り値を返すためだけに使用するわけではありません。return文がメソッドの中で実行されるとそれ以降の処理を実行せず呼び出し元へ処理が移すことができます。 次の例を見てください。 public static void main(String args[]){ int data[]; test(15, 4); test(7, 0); } private static void test(int n1, int n2){ if (n2 == 0){ System.out.println("0で割ることはできません"); return; } System.out.println(n1 + " / " + n2 + " = " + (n1 / n2)); return; }このメソッドでは2箇所でreturn文が使われています。1つ目はif文の中で使われていて、引数として渡されてきた2番目の値がもし0だった場合はメッセージを画面に表示した後でreturn文によってメソッドを終了させ呼び出し元に処理を戻しています。2つ目はメソッドの最後で使われており、処理が全て終わったらreturn文によってメソッドを終了させ呼び出し元に処理を戻しています。 このようにreturn文を使うことでメソッドの中の処理の流れを任意の位置で終了させ呼び出し元に処理を返すことができるようになります。 なおメソッドはブロック内の最後の文が実行され「}」に達するとメソッドの呼び出し元に処理が戻りますので、戻り値が無い場合にはメソッドの最後のreturn文は通常は記述する必要はありません。戻り値として返す値を指定する場合にだけ使用します。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample7_1{ public static void main(String args[]){ int data[]; test(15, 4); test(7, 0); } private static void test(int n1, int n2){ if (n2 == 0){ System.out.println("0で割ることはできません"); return; } System.out.println(n1 + " / " + n2 + " = " + (n1 / n2)); return; } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Method]$ java JSample7_1 15 / 4 = 3 0で割ることはできません [xxxxxxxx@dddddddddd Method]$ |
メソッドを引数を付けて呼び出す時、引数に記述する値のデータ型はメソッドで決められたものしか指定できません。その為、同じような機能を持つメソッドであっても引数のデータ型が異なれば別々のメソッドを用意する必要があります。 次の例を見てください。 public static void main(String args[]){ int n = plusInt(10, 7); System.out.println(n); double d = plusDouble(3.14, 7.4); System.out.println(d); } private static int plusInt(int n1, int n2){ return n1 + n2; } private static double plusDouble(double d1, double d2){ return d1 + d2; }この例ではint型の値の加算を行うメソッドとdouble型の値の加算を行うメソッドを2つ用意しています。これはこれで間違いではありません。ただ、同じような機能を持つメソッドであれば引数のデータ型が異なっていても同じメソッド名を使って呼び出せると便利です。そこでJavaではメソッドのオーバーロードという仕組みを利用します。 Javaでは引数のデータ型や引数の数が完全に一致していなければ異なるメソッドに同じメソッド名を付けることが出来ます。例えば先ほどの例は次のように記述することが可能です。 public static void main(String args[]){ int n = plus(10, 7); System.out.println(n); double d = plus(3.14, 7.4); System.out.println(d); } private static int plus(int n1, int n2){ return n1 + n2; } private static double plus(double d1, double d2){ return d1 + d2; }plusメソッドは同じクラスの中に2回定義されていますが、引数の数は同じでも引数のデータ型が異なるため区別することが可能です。メソッドを呼び出す側からはplusメソッドを呼び出した時に指定した引数のデータ型によってどちらのメソッドが呼び出されるのかが決まる事になります。 メソッド名を明確に分けたほうが便利な場合もありますが、メソッド名を同じにしておけば引数のデータ型を意識することなく利用することができます。例えばサンプルでもよく利用する「System.out.println(引数);」と言う文も、引数に整数を入れても文字列を入れても同じように画面に出力されるのは、このオーバーロードの仕組みを利用しています。 オーバーロードができる場合同じメソッド名で複数のメソッドを定義するには、引数の数が異なっているか、引数のデータ型が異なっている必要があります。○ 引数の数が異なっている場合: private static void test(int n1){ // ... } private static void test(int n1, int n2){ // ... }○ 引数の種類が異なっている場合: private static void test(int n1){ // ... } private static void test(double d1){ // ... }○ 引数のデータ型と数は同じでも順番が異なっている場合: private static void test(int n1, double d1){ // ... } private static void test(double d1, int n1){ // ... }このいずれかの条件さえ満たしていれば、同じメソッド名であっても2つまたそれ以上のメソッドを同じクラス内に定義することができます。 オーバーロードができない場合次にオーバーロードができない場合も確認しておきます。メソッド定義の時の引数の変数名だけが異なるようなものはオーバーロードできません。また戻り値の有る無しや戻り値のデータ型異なっているだけのものもオーバーロードすることはできません。 × 引数の変数名だけが異なっている場合: private static void test(int a){ // ... } private static void test(int b){ // ... }× 戻り値だけが異なっている場合: private static void test(int n){ // ... } private static int test(int n){ // return n; }このように変数名だけが異なっている場合や戻り値だけが異なっているメソッドを複数記述した場合は、コンパイルエラーとなり「(メソッド名) は (クラス名) で定義されています。」のようなエラーメッセージが表示されます。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample8_1{ public static void main(String args[]){ System.out.println(plus(10, 7)); System.out.println(plus(3.2, 4)); System.out.println(plus(7, 1.223)); System.out.println(plus(5.08, 2.4)); } private static int plus(int n1, int n2){ System.out.println("int + int"); return n1 + n2; } private static double plus(int n1, double d1){ System.out.println("int + double"); return n1 + d1; } private static double plus(double d1, int n1){ System.out.println("double + int"); return n1 + d1; } private static double plus(double d1, double d2){ System.out.println("double + double"); return d1 + d2; } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Method]$ java JSample8_1 int + int 17 double + int 7.2 int + double 8.223 double + double 7.48 [xxxxxxxx@dddddddddd Method]$引数のデータ型によって呼び出されるメソッドが決まっていることが確認できます。 |
JavaではJ2SE5.0のバージョンから新しく可変個の引数を持つメソッドを定義できるようになりました。書式は次の通りです。 public static void main(String args[]){ メソッド名(値1); メソッド名(値1, 値2); メソッド名(値1, 値2, 値3); } 修飾子 戻り値の型 メソッド名(データ型... 変数名){ /* メソッド内で実行する処理 */ }※メソッド定義の引数のところに書かれている「...」は省略を意味するものではなくドット「.」を3つ並べて記述します。 このメソッドの場合、メソッドを呼び出す時の引数を任意の数だけ記述することができるようになります。メソッド側では引数の箇所に記述した変数名を持つ配列を受け取ったように処理が行われます。 例えば次のように使用します。 public static void main(String args[]){ disp(10, 7, 8); } private static void disp(int... num){ for (int i = 0; i < num.length; i++){ System.out.println(num[i]); } }メソッドを呼び出す時に引数を3つ指定しています。メソッドを受け取る側では配列の要素に順に引数が格納されたかのように扱いますので、メソッド内では要素を参照することで引数を利用することができるようになります。 これは次のように記述した場合とほぼ同じです。 public static void main(String args[]){ int num[] = {10, 7, 8}; disp(num); } private static void disp(int num[]){ for (int i = 0; i < num.length; i++){ System.out.println(num[i]); } }なお、引数の数は任意ですが引数のデータ型は同じである必要があります。また引数は何個渡されてくるのかはメソッドが呼ばれるまで分かりませんので、引数の数を知るには「配列変数名.length」を使って配列の長さを取得して下さい。また可変引数の場合、引数は0であっても構いません。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample9_1{ public static void main(String args[]){ System.out.println(sum(4, 10)); System.out.println(sum(7, 2, 8)); System.out.println(sum()); } private static int sum(int... nums){ int sum = 0; for (int i = 0; i < nums.length; i++){ sum += nums[i]; } return sum; } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Method]$ java JSample9_1 14 17 0 [xxxxxxxx@dddddddddd Method]$ |
可変引数を使ってメソッドを定義した場合、通常の引数(可変引数に対して固定引数と呼ぶこともあります)と組み合わせることが可能です。 例えば次のように使用します。 public static void main(String args[]){ disp("[", "]", 10, 7, 8); } private static void disp(String sb, String sa, int... num){ for (int i = 0; i < nums.length; i++){ System.out.println(sb + num[i] + sa); } }この例ではStringクラスの引数を2つとint型の可変長の引数を組み合わせています。 固定引数と可変引数を組み合わせる場合の注意点は、必ず固定引数から記述する必要があることです。可変引数は一つのメソッドで一つしか記述できず、そして最後に記述しなければなりません。 では簡単な例で試しておきます。 サンプルプログラム下記のサンプルを実行してみよう。class JSample10_1{ public static void main(String args[]){ disp("[", "]", 10, 7, 8); disp("【", "】", 128, 76); } private static void disp(String sb, String sa, int... num){ for (int i = 0; i < num.length; i++){ System.out.println(sb + num[i] + sa); } } }上記をコンパイルした後で実行すると次のように表示されます。 [xxxxxxxx@dddddddddd Method]$ java JSample10_1 [10] [7] [8] 【128】 【76】 [xxxxxxxx@dddddddddd Method]$ |
|