簡體   English   中英

Java泛型和類型擦除

[英]Java generics and type erasure

給出以下代碼:

public void example(Object o) {
  if(o instanceof List<MyType>)
    //do something
}

我了解,鑒於Java處理泛型和類型擦除的方式,這是不可能的(以及為什么不可能如此)。

我的問題是,最佳/最干凈的方法是什么? 還是我唯一能做的就是檢查o是否為List<?>

您最多只能檢查一次o instanceof List<?>

從Java泛型獲得的類型安全性僅在編譯時發生。 像您這樣的方法(接受一個對象然后嘗試找出要做什么),在這種設計中效果不佳。 我可以看到為什么有時需要這樣的動態方法,但是可以考慮用類型化參數的版本來補充它:

public void example(Object o) {
  if(o instanceof List<?>)
     example((List)o);    // can only hope that the type is correct here
}

public void example(List<MyType> list){
    // do something
}

在可以使用它們的情況下,您將獲得泛型的全部好處。 在其他情況下,您必須依靠人們閱讀Javadoc並僅傳遞正確的類型。

甚至上面的方法也不能做到的是, List<TypeA>List<TypeB>具有兩個不同的代碼路徑。 如果確實需ListOfTypeA ,請考慮使用自己的包裝器類型ListOfTypeAListOfTypeB

根據您需要執行的操作,甚至可能根本沒有必要查看列表的已擦除類型,而只需要處理單個元素的運行時類型即可:

 for (Object o: list){
    if (o instanceof TypeA){
    }
    if (o instanceof TypeB){
    }
 }

如果不檢查List中所有項目的類型,就無法確定Java中通用參數的類型,因為它僅在編譯時存在,並在運行時刪除。

我的建議是,除非您絕對需要使該方法接受一個Object(例如符合接口規范或重寫Object.equals),然后將所需的正確類型作為該方法的參數,並使用您可能需要使用其他各種類型來運行該方法。

Java在編譯后會刪除泛型的類型信息,因此您不能以這種方式動態檢查類型參數。

如果此代碼的所有路徑都限制了type參數,請執行以下操作:

// Return true if object is a list of MyType, false if it is not a list, or is 
// empty
boolean isListOfMyType(Object o) {
    if (o instanceof List) {
        List<?> l = (List<?) o;
        return (l.size() > 0 && (l.get(0) instanceof MyType) 
    }
    return true;
}

是類型安全的,盡管僅在列表不為空時才起作用。 如果不是,則需要修改上面的內容以檢查所有項目是否都通過了instanceof test(如果列表中允許為null,則它們是否為null)。

另一種選擇是創建一個擴展了ArrayList<MyType>的子類,並將其用於您的instanceof檢查。

最后但並非最不重要的是,有一個實現List<MyType>的子類將使您可以使用Class.getGenericInterfaces()方法獲得type參數。 請參閱了解詳情。

對於這兩種最后一種方法,您必須確保列表的創建始終實例化這些類型之一。 就是 如果調用方去構建自己的ArrayList<MyType> ,它將無法正常工作。

與被廣泛接受且很少為人所知的類型擦除相反,可以避免這種情況,這意味着被調用者確實能夠知道在調用過程中使用了哪些通用參數。

請看一下: 使用TypeTokens檢索通用參數

謝謝

也許通過在運行時檢查對象類型,也許像:

if (o.getClass() == List.class) ...

顯然,您必須更深入地研究對象的類類型,以查看它是否與List<>和列表的元素類型完全匹配。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM