我看到的所有文章都表明Eclipse是正确的,这段代码不行.但是当使用javac进行编译并运行时,将选择正确的方法.
这怎么可能?
谢谢!
import java.util.ArrayList; public class Test { public static void main (String [] args) { Test t = new Test(); ArrayList<String> ss = new ArrayList<String>(); ss.add("hello"); ss.add("world"); ArrayList<Integer> is = new ArrayList<Integer>(); is.add(1); is.add(2); System.out.println(t.getFirst(ss)); System.out.println(t.getFirst(is)); } public String getFirst (ArrayList<String> ss) { return ss.get(0); } public Integer getFirst (ArrayList<Integer> ss) { return ss.get(0); } }
解决方法
It is a compile-time error to declare two methods with
override-equivalent signatures
(defined below) in a class.Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.
The signature of a method m1 is a subsignature of the signature of a method m2 if either
m2 has the same signature as m1,or
the signature of m1 is the same as the erasure of the signature of m2.
很明显,这些方法不是覆盖等价的,因为ArrayList< String>不是ArrayList(ArrayList< Integer>的擦除).
所以宣称这些方法是合法的.此外,方法调用表达式是有效的,因为这是一个最具体的方法,因为只有一种匹配参数类型的方法.
编辑:沂山正确地指出,在这种情况下,还有另外一个限制. Java Language Specification,section 8.4.8.3写道:
It is a compile time error if a type declaration T has a member method
m1 and there exists a method m2
declared in T or a supertype of T such
that all of the following conditions
hold:
- m1 and m2 have the same name.
- m2 is accessible from T.
- The signature of m1 is not a subsignature (§8.4.2) of the signature of m2.
- m1 or some method m1 overrides (directly or indirectly) has the same erasure as m2 or some method m2 overrides (directly or indirectly).
附录:关于呃,还有它的缺乏
与流行概念相反,方法签名中的泛型不会被清除.泛型被字节码(Java虚拟机的指令集)擦除.方法签名不是指令集的一部分;它们被写入源代码中指定的类文件. (除此之外,还可以在运行时使用反射查询此信息).
想想一下:如果类型参数完全从类文件中删除,那么您选择的IDE中的代码完成如何可以显示ArrayList.add(E)接受类型为E的参数,而不是Object(= E的擦除)如果您没有附加JDK源代码?当方法参数的静态类型不是E的子类型时,编译器如何知道抛出编译错误?