这取决于您希望如何调用这些方法。如果您希望从其他 Java 源代码调用这些方法,那么由于Edwin's answer 中说明的原因,它被认为是无效的。这是 Java 语言的限制。
但是,并非所有类都需要从 Java 源代码生成(考虑使用 JVM 作为其运行时的所有语言:JRuby、Jython 等...)。 在字节码级别,JVM 可以消除这两种方法的歧义,因为字节码指令指定了它们所期望的返回类型。例如,这里有一个用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 发布了调用这些方法的an example program:
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”
类 RealyCompilesAndRunsFine 扩展 java.lang.Object{
RealyCompilesAndRunsFine();
代码:
0:aload_0
1:调用特殊#1; //方法 java/lang/Object."":()V
4:返回
公共静态 java.lang.String f(java.util.List);
代码:
0:aload_0
1:iconst_0
2:调用接口#2、2; //接口方法 java/util/List.get:(I)Ljava/lang/Object;
7:检查广播#3; //类java/lang/String
10:返回
公共静态 java.lang.Integer f(java.util.List);
代码:
0:aload_0
1:iconst_0
2:调用接口#2、2; //接口方法 java/util/List.get:(I)Ljava/lang/Object;
7:检查广播#4; //类 java/lang/Integer
10:返回
公共静态无效主(java.lang.String[]);
代码:
0:iconst_1
1:新数组#3; //类java/lang/String
4:重复
5:iconst_0
6:最不发达国家#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:astore_1
16:图标st_1
17:新阵列#4; //类 java/lang/Integer
20:重复
21:iconst_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:astore_2
35:获取静态#10; //字段 java/lang/System.out:Ljava/io/PrintStream;
38:加载_1
39:调用虚拟#11; //方法java/io/PrintStream.println:(Ljava/lang/String;)V
42:获取静态#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 Language Specification 表明这实际上可能是有效的 Java 源代码。在第 449 页(第 15.12 节方法调用表达式)我们看到:
可能没有最具体的方法,因为有两种或
更多最具体的方法。在这种情况下:
- 如果所有最具体的方法都有覆盖等效(第 8.4.2 节)签名,
然后:
- 如果没有将最具体的方法之一声明为抽象的,
这是最具体的方法。
- 否则,如果所有最具体的方法都被声明为抽象的,
并且所有最大特定方法的签名具有相同的
擦除(§4.6),然后在其中任意选择最具体的方法
具有最具体的最具体方法的子集
返回类型。然而,最具体的方法被认为是抛出一个
当且仅当该异常或其擦除在
每个最具体的方法的 throws 子句。
- 否则,我们说方法调用有歧义,编译时
发生错误。
除非我弄错了,否则这种行为应该只适用于声明为抽象的方法...
更新 #3
感谢 ILMTitan 的评论:
@Adam Paynter:你的粗体字是
没关系,因为这只是一个案例
当有两种方法时
覆盖等效,丹显示
情况并非如此。就这样
决定因素必须是如果 JLS
考虑泛型类型时
确定最具体的方法。 –
ILM钛