Dee*_*ech 9 java eclipse generics javac
我有以下测试类,它使用泛型来重载方法.它在使用javac编译时有效,无法在Eclipse Helios中编译.我的java版本是1.6.0_21.
我读到的所有文章都表明Eclipse是对的,这段代码不适用.但是,使用javac和run编译时,会选择正确的方法.
这怎么可能?
谢谢!
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);
}
}
Run Code Online (Sandbox Code Playgroud)
在Java语言规范,第8.4.2节写道:
在类中声明具有覆盖等效签名(在下面定义)的两个方法是编译时错误.
如果m1是m2的子签名或m2是m1的子签名,则两个方法签名m1和m2是覆盖等价的.
方法m1的签名是方法m2的签名的子签名(如果有的话)
m2与m1具有相同的签名,或
m1的签名与m2的签名擦除相同.
显然,这些方法不是覆盖等价的,因为ArrayList<String>它不是ArrayList(擦除ArrayList<Integer>).
因此宣布这些方法是合法的.此外,方法调用表达式是有效的,因为通常只有一个方法匹配参数类型,因此通常是最具体的方法.
编辑:Yishai正确地指出在这种情况下还有另一个限制.在Java语言规范,部分8.4.8.3写道:
如果类型声明T具有成员方法m1并且存在以T形式声明的方法m2或T的超类型以使得满足以下所有条件,则为编译时错误:
- m1和m2具有相同的名称.
- m2可从T访问.
- m1的签名不是m2签名的子签名(第8.4.2节).
- m1或某些方法m1覆盖(直接或间接)具有与m2相同的擦除或某种方法m2覆盖(直接或间接).
附录:关于实现,以及缺乏
与流行的概念相反,方法签名中的泛型不会被删除.泛型以字节码(Java虚拟机的指令集)擦除.方法签名不是指令集的一部分; 它们被写入源代码中指定的类文件中.(另外,也可以在运行时使用反射查询此信息).
想一想:如果类型参数完全从类文件中删除,那么如果您没有JDK源,那么您所选择的IDE中的代码完成如何显示ArrayList.add(E)带有类型的参数E,而不是Object(=擦除E)附加代码?当方法参数的静态类型不是子类型时,编译器如何知道抛出编译错误E?
如果 javac 有 bug,那也是有可能的。Javac 只是软件,与任何其他软件一样容易出现错误。
另外,Java 语言规范非常复杂,并且在某些地方有点模糊,因此这也可能是由于 Eclipse 人员和 javac 人员之间的解释差异所致。
我首先会在 Eclipse 支持渠道上询问这个问题。他们通常非常善于发现这些事情并解释为什么他们认为自己是对的,或者承认自己是错的。
根据记录,我认为 Eclipse 也在这里。
| 归档时间: |
|
| 查看次数: |
2632 次 |
| 最近记录: |