簡體   English   中英

如何指定集合的泛型類型?

[英]How to specify the generic type of a collection?

我想定義一個 function 可以將一種 Set 轉換為另一種,例如將 HashSet 轉換為 LinkedHashSet。 這是 function 聲明。 sp 是共享首選項。

public Set<String> decodeStringSet(String key, @Nullable Set<String> defaultValue, Class<? extends Set> cls){
    Set<String> result = sp.getStringSet(key, defaultValue);
    if(result == null){
        return defaultValue;
    }
    else {
        String[] array = result.toArray(new String[0]);
        Set<String> a;
        try {
            a = cls.newInstance();
        } catch (IllegalAccessException | InstantiationException var7) {
            return defaultValue;
        }

        a.addAll(Arrays.asList(array));
        return a;
    }
}

但是,編譯器提醒我“a = cls.newInstance();”上的“未經檢查的賦值:'?將 java.util.Set' 擴展為 'java.util.Set<java.lang.String>'”。 我不知道如何將 cls 更改為 cls<java.lang.String>。

警告是不可避免的。 將它隔離在一個輔助方法中,並向它扔適當的@SuppressWarnings 或者,重構這個東西是如何工作的。 一般來說, Class<?>的 generics 很奇怪,不能正常工作; 如果您嘗試編寫依賴 generics 部件使其工作的代碼,則可能會導致您無法避免這些警告的許多情況,並且 API 不是最理想的。 1

以一種千篇一律的方式來做你想做的事情的一種棘手方法是所謂的超級類型令牌。 你可以在 web 中搜索這個概念,因為對於你在這里具體做的事情,STT 是多余的。 您正在尋找的是供應商

您希望調用者不要將集合的類型傳遞給您。 不。您希望調用者將一段代碼傳遞給您,如果執行該代碼,則會創建該集合。

當我們這樣做時,讓我們擺脫數組,您完全沒有合理的理由在該數組中移動元素。

public <S extends Set<String>> S decodeStringSet(String key, @Nullable Set<String> defaultValue, Supplier<S> setMaker) {
    Set<String> result = sp.getStringSet(key, defaultValue);
    if(result == null) return defaultValue;

    S a = setMaker.get();
    a.addAll(result);
    return a;
}

此代碼可按如下方式使用:

LinkedHashSet<String> mySet = decodeStringSet("myKey", null, LinkedHashSet::new);

也許你不熟悉這種語法。 new LinkedHashSet()將在您運行該代碼時創建一個 LinkedHashSet。 相反,當您運行該代碼時, LinkedHashSet::new將生成一個 object,可以通過調用它的get()方法來要求創建一個 LinkedHashSet。 一個人在這一刻做正確的事。 另一個將“行動”包裝成一台小機器。 您可以將機器交給其他代碼,或者按下機器上的按鈕使其執行操作,並且您可以根據需要隨時按下按鈕。


[1] 需要更多解釋為什么依賴 jlClass 的jlClass很尷尬而且不是一個好主意?

A class object simply cannot , itself, represent generics, whereas generics can represent generics. 也就是說: List<List<String>>非常好。 但是, Class<List<String>>沒有意義。 你可以寫它,(jlClass 沒有硬編碼規則來保持 langspec 中的理智),但它不代表任何東西:只有一個 class object 代表了類型juList 因此這個 object 不能代表 generics; 你不能有一個 class object 代表List<String>和另一個代表List<Integer> 不太重要,但仍然很煩人 - class 對象可以表示 generics 不能。 int.class的類型為Class<Integer>但這不太正確。

因此,在您的示例中,編譯器考慮Class<? extends Set> Class<? extends Set>有問題; generics 中有一個原始類型。 但是,它在技術上是正確的,因為它不可能表示例如Set<T> ,而只能表示“一個集合,其 generics 是未知的,因為 jlClass 對象不能表示它們”。

最后,類基本上只產生(PECS 中的 P - 這解釋了<Number><? extends Number><? super Number>之間的區別); 很難理解Class<? extends String> Class<? extends String>Class<String> ,因為這是一個無關緊要的區別,因為 jlClass 只產生。 然而,通常你確實需要編寫Class<? extends String> Class<? extends String>因為如果你不這樣做,編譯器會出於虛構的、不相關的原因拒絕編譯你的代碼。 那是因為 jlClass 在語言規范中沒有硬編碼:編譯器不知道Class<T>Class<? extends T> Class<? extends T> ,並且 java 沒有辦法將給定的 generics 參數標記為強制僅生產或類似的。

暫無
暫無

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

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