我惊讶地发现下面编译Java类。 它有几种方法,具有相同的名称,参数数量和以下类型的参数擦除类型。但是,它使用各种版本的Sun JDK 1.6编译器在Windows上编译并按预期工作。所以,如果这是一个错误就已经行之有年....
它也与Eclipse的众多版本的编译,但是不与编译器编译附带的Eclipse 3.6
除了调用代码按预期工作 - 即。关于调用代码的隐含方法没有任何错误。
如果您遍历通过ErasureExample.class.getMethods(),他们都存在.....
按照JLS这将是非法的,如果方法具有“覆盖相当于”签名返回的方法 - 严格地说,他们不这样做,因为没有收集,收集或集合都没有被覆盖的等价物....如果是这种情况,Eclipse是错误的,JDK正确...
功能或错误? 它应该编译?
/**
* Demonstrates that a class with methods that differ only by return type can exist.
* Section 8.4 of the JLS suggests this is an error IFF the methods had
* override equivalent signatures, which they dont''
*
*
* From JLS 8.4...
* It is a compile-time error for the body of a class to declare as members two methods
* with override-equivalent signatures (§8.4.2) (name, number of parameters, and types
* of any parameters).
*
* Should it compile?
*/
public class ErasureExample {
// note the single Collection<Integer> argument...
public static int[] asArray(Collection<Integer> vals) {
if (vals == null)
return null;
int idx = 0;
int[] arr = new int[vals.size()];
for (Integer i : vals) {
arr[idx] = i==null? 0 : i.intValue();
idx++;
}
return arr;
}
// same method name as above, type differs only by generics.... surely this violates 8.4 of JLS...
public static long[] asArray(Collection<Long> vals) {
if (vals == null)
return null;
int idx = 0;
long[] arr = new long[vals.size()];
for (Long i : vals) {
arr[idx] = i==null? 0 : i.longValue();
idx++;
}
return arr;
}
// same method name as above, type differs only by generics.... surely this violates 8.4 of JLS...
public static boolean[] asArray(Collection<Boolean> vals) {
if (vals == null)
return null;
int idx = 0;
boolean[] arr = new boolean[vals.size()];
for (Boolean b : vals) {
arr[idx] = b==null? false : b.booleanValue();
idx++;
}
return arr;
}
}
更正:返回值不是签名的一部分 – schar 2010-07-15 17:20:11
实际上,在字节码级别,方法描述符也包含返回类型,并且可以用来区分它们。编译器有时可以利用这一点,通过检查你保存结果的变量的类型,因为编译器可以知道应该调用哪个方法,而在字节码中,它只是指令'带有描述符的调用方法this-and-那'。根据规范,它不完全正确,但编译器现在允许它。显然在Java 7中,他们可能会改变这一点。 – 2010-07-15 17:57:36
用这段代码玩了一会之后,我发现Andrei Fierbinteanu最有说服力的解释。编译具有相同签名的方法似乎没有实际问题,因为字节码中的调用是基于方法的唯一数字ID。一些编译器利用它们具有通用信息的事实来实现这一点。这会导致问题。例如,参见反射:ErasureExample.class.getDeclaredMethod(“asArray”,Collection.class)返回源代码中的第一个方法!(即重新排序代码改变事物) – 2010-07-15 19:12:35