2010-07-15 72 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

編譯器足夠聰明,可以在編譯時消除這些方法,儘管最終它會執行類型擦除。參數化泛型的要點是提供編譯時類型安全檢查,類型擦除只是一個實現細節。