【はじめてのJava】オーバーロードの注意点【オブジェクトとクラス編】
はじめてのJava
このシリーズでは、初めてJavaやプログラミングを勉強する方向けに、Javaによるプログラミングの基礎を説明していきます。
目標レベルは、Javaの資格試験の一つである「Oracle Certified Java Programmer, Silver」(通称Java Silver)に合格できる程度の知識の習得です。
はじめてJavaやプログラムに触れる方にもできるだけわかりやすい解説を心がけていきます。
オブジェクトとクラス編
オブジェクトとクラス編では、Javaを扱う上で非常によく出てくる「オブジェクト」や「クラス」について扱っていきます。
前回は「オーバーロード」について扱いました。
今回は「オーバーロードの注意点」について扱います。
なお、本記事は筆者環境で実際に試した内容をもとに執筆しています。Javaのバージョンなどが変わると実行結果が変わる可能性もありますのでご注意ください。
筆者環境
javacのバージョン
javac 11
javaのバージョン
openjdk 11 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
目次
戻り値の注意点
オーバーロードの際、戻り値そのものには注意点はありません。ただし、 戻り値の違いのみでメソッドのオーバーロードを定義することはできません 。
これは戻り値が違っていても、引数が同じ場合はメソッドの呼び出し時にどちらのメソッドを呼び出しているのか区別ができないためです。
もし戻り値の違いのみでメソッドをオーバーロードしようとするとコンパイルエラーになります。
具体例を見てみましょう。以下のSampleクラスでは、method()メソッドをオーバーロードしています。
コメントアウトされている「String method(int a)」というメソッドは、直前の「int method(int a)」というメソッドと引数での区別ができないためコンパイルエラーになります。
残りのmethod()メソッドは、戻り値の違いは関係なく、引数がほかのメソッドと異なっているのでオーバーロードとして有効です。
Sample.java
public class Sample{ int method(){ System.out.println("int method()"); return 0; } //OK int method(int a){ System.out.println("int method(int a)"); return 1; } //戻り値のデータ型が異なっても引数で↑のmethodと区別できないためコンパイルエラー //String method(int a){ // System.out.println("String method(int a)"); // return "message"; //} //OK Integer method(int a, int b){ System.out.println("Integer method(int a, int b)"); return 2; } //OK void method(int a, int b, int c){ System.out.println("void method(int a, int b, int c)"); return; } //OK String method(int a, int b, int c, int d){ System.out.println("String method(int a, int b, int c)"); return "message"; } }
動作確認用のmainメソッドの入ったクラスは以下の通りです。2つのファイルを一緒のディレクトリに保存してコンパイル、実行してください。
public class SampleMain{ public static void main(String[] args){ Sample s = new Sample(); //インスタンス化 s.method(); s.method(1); s.method(1,2); s.method(1,2,3); s.method(1,2,3,4); } }
実行結果は以下の通りです。
引数の注意点
引数の数、引数の順番、引数のデータ型、の違いによってどのメソッドを呼び出しているのか区別できればオーバーロードとして有効です。
逆に言えば、 引数の違いからどのメソッドを呼び出しているのか区別できないといけません 。
public class Sample{ //1 元のメソッド int method(){ System.out.println("method()"); return 1; } //2 OK 引数が異なるので呼び分け可能 int method(int a){ System.out.println("method(int)"); return 2; } //3 NG 引数名が2と異なるが、データ型が一緒なので2と呼び分け不可 //int method(int num){ // System.out.println("method(int)"); // return 3; //} //4 OK 同じ整数型だが、データ型は異なるということになるので呼び分け可能 int method(short a){ System.out.println("method(short)"); return 4; } //5 OK 同じ整数型だが、データ型は異なるということになるので呼び分け可能 int method(long a){ System.out.println("method(long)"); return 5; } //6 OK int型のラッパークラスだが、データ型は異なるということになるので呼び分け可能 int method(Integer a){ System.out.println("method(Integer)"); return 6; } //7 OK Integer型の親クラスだが、6番とはデータ型は異なるということになるので呼び分け可能 int method(Object a){ System.out.println("method(Object)"); return 7; } //8 OK ComparableはInteger型で実装しているインタフェイスだが、6番とはデータ型は異なるので呼び分け可能 int method(Comparable a){ System.out.println("method(Comparable)"); return 8; } //9 OK 配列はもとのデータ型とは異なるデータ型扱いなので呼び分け可能 int method(int[] a){ System.out.println("method(int[])"); return 9; } //10 ※ 可変長引数 配列を引数に取るメソッド(9番)が無ければOK。今回は9との呼び分けができない。詳しくは可変長引数の回で説明。 //int method(int... a){ // System.out.println("method(int...)"); // return 10; //} //11 OK 引数が異なるので呼び分け可能 int method(int a, int b, String str){ System.out.println("method(int, int, String)"); return 11; } //12 NG 引数名が11と異なるが、データ型の順番が11と一緒なので、呼び分けできない //int method(int num, int num2, String msg){ // System.out.println("method(int, int, String)"); // return 12; //} //13 NG 引数名が11と一緒で、一部順番が入れ替わっているが、データ型の順番が元のメソッドと一緒なので、呼び分けできない。 //int method(int b, int a, String str){ // System.out.println("method(int, int, String)"); // return 13; //} //14 OK 引数名は11と一緒だが、データ型の順番の違いから11とは呼び分け可能 int method(int a, String str, int b){ System.out.println("method(int, String, int)"); return 14; } }
動作確認用のmainメソッドの入ったクラスは以下の通りです。2つのファイルを一緒のディレクトリに保存してコンパイル、実行してください。
public class SampleMain{ public static void main(String[] args){ Sample s = new Sample(); //インスタンス化 s.method(); //1番 s.method(1); //2番 s.method((short)4); //4番 s.method(5L); //5番 s.method(new Integer(6)); //6番 s.method(new Object()); //7番 s.method((Comparable)(new Integer(8))); //8番 s.method(new int[]{1,2,3}); //9番 s.method(1,2,"hello"); //11番 s.method(1,"hello", 2); //14番 } }
実行結果は以下の通りです。
まとめ
引数のデータ型の順番によって区別が可能であればオーバーロードとして成り立つ。
次回
次回はコンストラクタについて扱います。
はじめてのJavaシリーズの目次はこちら
オブジェクトとクラス編はこちら