2010-07-15 58 views
7

可能重复:
Is this valid Java?功能或错误:为什么要编译此Java代码?

我惊讶地发现下面编译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; 
    } 

} 

回答

-3

这些方法根本没有相同的签名。不同的返回值和不同的参数类型。确实,泛型确实有很大的不同。这里一切看起来不错。

+7

更正:返回值不是签名的一部分 – schar 2010-07-15 17:20:11

+5

实际上,在字节码级别,方法描述符也包含返回类型,并且可以用来区分它们。编译器有时可以利用这一点,通过检查你保存结果的变量的类型,因为编译器可以知道应该调用哪个方法,而在字节码中,它只是指令'带有描述符的调用方法this-and-那'。根据规范,它不完全正确,但编译器现在允许它。显然在Java 7中,他们可能会改变这一点。 – 2010-07-15 17:57:36

+1

用这段代码玩了一会之后,我发现Andrei Fierbinteanu最有说服力的解释。编译具有相同签名的方法似乎没有实际问题,因为字节码中的调用是基于方法的唯一数字ID。一些编译器利用它们具有通用信息的事实来实现这一点。这会导致问题。例如,参见反射:ErasureExample.class.getDeclaredMethod(“asArray”,Collection.class)返回源代码中的第一个方法!(即重新排序代码改变事物) – 2010-07-15 19:12:35

2

编译器足够聪明,可以在编译时消除这些方法,尽管最终它会执行类型擦除。参数化泛型的要点是提供编译时类型安全检查,类型擦除只是一个实现细节。