我驚訝地發現下面編譯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