這個問題在這里已經有了答案: 什么是原始型別,為什么我們不應該使用它? (15 個回答) 2天前關閉。
語境
我有一個Job包含單個方法的介面,如下所示。
@FunctionalInterface
public interface Job {
public void run() throws Exception;
}
在我的一堂課中,我有一個Jobs這樣的串列:
class MyClass<A, B, C, D, E, F> { // I know, it's a large number of generic types
transient final ArrayList<Job> hooks;
/* Constructor */
public MyClass(){
hooks = new ArrayList<>();
}
}
問題
從與 同一個包中的另一個類MyClass,我試圖回圈訪問 member 的內容,hooks如下所示:
class DifferentClass {
@SuppressWarnings("rawtypes")
void procedure(MyClass a){
for (final Job h : a.hooks) { // Compilation error here
try {
h.run();
} catch (Exception e) {
}
}
}
但是 Eclipse 編譯器不允許我這樣做。我收到以下錯誤:
型別不匹配:無法從元素型別 Object 轉換為 Job
但是,如果上述回圈在類的方法中,MyClass則編譯器不會抱怨:
class MyClass<A, B, C, D, E, F> { // I know, it's a large number of generic types
transient final ArrayList<Job> hooks;
void procedureInClass() {
for (final Job h : hooks) { // No compilation error in this case
try {
h.run();
} catch (Exception e) {
}
}
}
/* Constructor */
public MyClass(){
hooks = new ArrayList<>();
}
}
更令人困惑的是,如果我從命令列使用mavenand編譯我的專案OpenJDK v1.8.0_312,我的專案在這兩種情況下都可以毫無問題地編譯。
問題
是什么阻止了MyClass#hooks在 Eclipse IDE 中從該類外部回圈訪問成員的內容?
(編輯)在非常有用的評論之后,我添加了@SuppressWarnings我最初省略的泛型型別 /。
uj5u.com熱心網友回復:
這是因為通過宣告a為MyClass沒有通用規范,您將其宣告為原始型別
通常我們習慣于List<SomeType>泛型,即在運行時進行型別擦除。此外,如果我們有舊代碼,例如:
List myRawTypeVariable = new ArrayList();
那myRawType是一個原始型別,因為我們可以添加任何型別,Object并且只能將Objects 取出。
然而,事實證明(正如您所發現的)原始型別比這更進一步,并且型別擦除也具有編譯時含義。
Java 語言規范 (JLS) 說明了這一點(來源:https ://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.8 )
未從其超類或超介面繼承的原始型別 C 的建構式(第 8.8 節)、實體方法(第 8.4 節、第 9.4 節)或非靜態欄位(第 8.3 節)的型別是對應于的原始型別在對應于 C 的泛型宣告中擦除其型別。
請注意,這并不是將型別擦除僅限于泛型型別;所有實體方法的型別都被帶到它們的原始型別!
換句話說,通過不指定 的泛型型別MyClass,您正在創建MyClass一個原始型別 - 因此關閉該類的所有泛型型別檢查(除了方法等,否則從繼承或介面中指定)。
因此,即使hooks被宣告為 a List<Job>,因為您將MyClass其用作原始型別,它也會洗掉<Job>泛型并將該方法視為簡單地回傳 a List(實際上是 a List<Object>)。
所以解決方法是添加通用說明符,所以:
void procedure(MyClass<?> a){
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/461574.html
