これらのメソッドをどのように呼び出すかによって異なります。これらのメソッドを他の Java ソース コードから呼び出したい場合は、 Edwin の回答に示されている理由から無効と見なされます。これは Java 言語の制限です。
ただし、すべてのクラスを Java ソース コードから生成する必要があるわけではありません (JVM をランタイムとして使用するすべての言語を考慮してください: JRuby、Jython など...)。バイトコード レベルでは、JVM は 2 つのメソッドのあいまいさを解消できます。これは、バイトコード命令が期待する戻り値の型を指定しているためです。たとえば、これらのメソッドのいずれかを呼び出すことができるJasminで記述されたクラスを次に示します。
.class public CallAmbiguousMethod
.super java/lang/Object
.method public static main([Ljava/lang/String;)V
.limit stack 3
.limit locals 1
; Call the method that returns String
aconst_null
invokestatic TestWillThatCompile/f(Ljava/util/List;)Ljava/lang/String;
; Call the method that returns Integer
aconst_null
invokestatic TestWillThatCompile/f(Ljava/util/List;)Ljava/lang/Integer;
return
.end method
次のコマンドを使用して、クラス ファイルにコンパイルします。
java -jar jasmin.jar CallAmbiguousMethod.j
そして、次を使用して呼び出します。
java CallAmbiguousMethod
見よ、出力は次のとおりです。
> Java CallAmbiguousMethod
文字列
数字
アップデート
Simon は、これらのメソッドを呼び出すサンプル プログラムを投稿しました。
import java.util.Arrays;
import java.util.List;
class RealyCompilesAndRunsFine {
public static String f(List<String> list) {
return list.get(0);
}
public static Integer f(List<Integer> list) {
return list.get(0);
}
public static void main(String[] args) {
final String string = f(Arrays.asList("asdf"));
final Integer integer = f(Arrays.asList(123));
System.out.println(string);
System.out.println(integer);
}
}
生成された Java バイトコードは次のとおりです。
>javap -c RealyCompilesAndRunsFine
「RealyCompilesAndRunsFine.java」からコンパイル
class RealyCompilesAndRunsFine extends java.lang.Object{
RealyCompilesAndRunsFine();
コード:
0: aload_0
1: 特別な #1 を呼び出します。//メソッド java/lang/Object."":()V
4: 戻る
public static java.lang.String f(java.util.List);
コード:
0: aload_0
1: アイコンスト_0
2: 呼び出しインターフェイス #2、2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
7: チェックキャスト #3; //クラス java/lang/String
10: 戻る
public static java.lang.Integer f(java.util.List);
コード:
0: aload_0
1: アイコンスト_0
2: 呼び出しインターフェイス #2、2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
7: チェックキャスト #4; //クラス java/lang/Integer
10: 戻る
public static void main(java.lang.String[]);
コード:
0: アイコンスト_1
1: 新たな配列 #3; //クラス java/lang/String
4: 複製
5: アイコンスト_0
6: ldc #5; //文字列 asdf
8: アストア
9: インボークスタティック #6; //メソッド java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
12: インボークスタティック #7; //メソッド f:(Ljava/util/List;)Ljava/lang/String;
15: アストア_1
16: アイコンスト_1
17: 新たな配列 #4; //クラス java/lang/Integer
20: 重複
21: アイコンスト_0
22:バイプッシュ123
24: インボークスタティック #8; //メソッド java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
27: アーストア
28: インボークスタティック #6; //メソッド java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
31: インボークスタティック #9; //メソッド f:(Ljava/util/List;)Ljava/lang/Integer;
34: アストア_2
35: getstatic #10; //フィールド java/lang/System.out:Ljava/io/PrintStream;
38: アロード_1
39: インボークバーチャル #11; //メソッド java/io/PrintStream.println:(Ljava/lang/String;)V
42: getstatic #10; //フィールド java/lang/System.out:Ljava/io/PrintStream;
45: アロード_2
46: インボークバーチャル #12; //メソッド java/io/PrintStream.println:(Ljava/lang/Object;)V
49: 戻る
メソッドのあいまいさを解消するために必要なバイトコードを Sun コンパイラが生成していることがわかります (最後のメソッドの手順 12 と 31 を参照)。
アップデート #2
Java 言語仕様は、これが実際には有効な Java ソース コードである可能性があることを示唆しています。449 ページ (§15.12 メソッド呼び出し式) に、次のように記載されています。
最も具体的なメソッドが 2 つ以上あるため、最も具体的なメソッドがない可能性があります。この場合:
- すべての最大限に具体的なメソッドにオーバーライドと同等の (§8.4.2) 署名がある場合、次のようになります。
- 最大限に具体的なメソッドの 1 つだけが抽象として宣言されていない場合、それは最も具体的なメソッドです。
- それ以外の場合、すべての最大に固有のメソッドが抽象として宣言され、すべての最大に固有のメソッドの署名が同じ消去 (§4.6) を持つ場合、最も固有のメソッドは、最大に固有のメソッドのサブセットの中から任意に選択されます。最も具体的な戻り値の型。ただし、最も具体的なメソッドは、その例外またはその消去が最大限に具体的な各メソッドの throws 句で宣言されている場合にのみ、チェック済み例外をスローすると見なされます。
- それ以外の場合、メソッド呼び出しがあいまいであると言い、コンパイル時エラーが発生します。
私が間違っていない限り、この動作は抽象として宣言されたメソッドにのみ適用されます...
アップデート #3
ILMTitan のコメントに感謝します。
@Adam Paynter: 太字のテキストは重要ではありません。これは、2 つのメソッドがオーバーライドと同等である場合のみであり、Dan が示したのはそうではなかったからです。したがって、決定要因は、JLS が最も具体的なメソッドを決定するときにジェネリック型を考慮に入れるかどうかでなければなりません。– ILMチタン