簡體   English   中英

泛型:輸入變量?

[英]Generics: Type as variable?

為了能夠替代特定的實現,通常知道寫

List<AnyType> myList = new ArrayList<AnyType>();

代替

ArrayList<AnyType> myList = new ArrayList<AnyType>();

這很容易理解,這樣您可以輕松地將實現從ArrayList更改為LinkedList或任何其他類型的List。

嗯......這一切都很好,但由於我不能直接實例化“List”,因此我需要輸入

public List<AnyType> getSpecificList()
{
    return new ArrayList<AnyType>();
}

這使得以前的模式毫無意義。 如果我現在想用LinkedList而不是ArrayList替換實現怎么辦? 它需要在兩個位置上進行更改。

有可能有這樣的東西(我知道語法絕對不正確)?

public class MyClass<T>
{
    Type myListImplementation = ArrayList;

    List<T> myList = new myListImplementation<T>();

    public List<T> getSpecificList()
    {
        return new myListImplementation<T>();
    }
}

這將允許我簡單地將單詞“ArrayList”更改為“LinkedList”,一切都很好。 我知道這兩個列表可能有不同的構造函數,這不會“按原樣”工作。 我真的不想添加第二個類型參數來指定正在使用的列表實現。

是否有任何干凈的機制來解決這個問題?^

在此先感謝和最好的問候Atmocreations

為什么不使用某種工廠模式而不是直接實例化特定的列表實現。 然后,您需要在工廠方法內的一個位置更改列表實現。

例如,您從以下開始:

 List<T> createList() {
     return new ArrayList<T>();
 } 

 List<T> myList1 = createList();
 List<T> myList2 = createList();

稍后,如果您決定需要鏈接列表,則只需更改createList()的實現,其余代碼保持不變。

List<T> createList() {
    return new LinkedList<T>();
}

嗯 - 據我了解你的問題,你想做的事情已經成為可能(與泛型無關)。

在實際進行構造函數調用時,您總是需要給出列表(或任何類)的確切類型,這是不可避免的。 同樣,您始終可以避免在其他任何地方使用特定內容(將其存儲在變量中,從方法返回,將其作為方法參數傳遞等)。 在你的情況下,你已經這樣做 - 通過將myList聲明為List,如果你改變你存儲在其中的具體類列表,你不需要改變它的聲明類型。

我認為你的問題可能是因為你在同一個類中創建了兩個不同的列表(但是它們都是相同的類型),並且你想要抽象出來。 您可以使用工廠類型模式輕松完成此操作; 或者使用單獨的工廠,或者在您的情況下,只需用myList聲明替換

List<T> myList = getSpecificList();

編輯 - 出於興趣,你可以得到最接近原始建議修復的東西是使用反射:

public class MyClass<T>
{
    Class<? extends List<T>> myListClass = ArrayList.class;

    List<T> myList = myListClass.newInstance();

    public List<T> getSpecificList()
    {
        return myListClass.newInstance();
    }
}

但是不要這樣做 - 它是緩慢的,不靈活的,不尋常的(對於其他開發人員來說太難了)在這種情況下完全沒有必要......

雙重編輯:哦,你必須處理一大堆基於反射的檢查異常,我將這些異常作為練習留給讀者,以防你感到受到誘惑。 ;-)

如果我現在想用LinkedList而不是ArrayList替換實現怎么辦? 它需要在兩個位置上進行更改。

不,你不會。 您可以單獨更改每個位置。 即,其中一個分配可以是LinkedList,另一個可以是ArrayList。

這實際上與泛型無關,而是與多態性有關

使用List (或List<T> )而不是ArrayList (或ArrayList<T> )的關鍵是List是一個接口,ArrayList是一個具體的實現。 接口很好,您應該使用它們,但它們實際上與泛型無關。

在您的示例中,為什么需要將List的實際類型變為變量? 如果你真的想抽象出對象的創建,你應該使用一個工廠方法,就像你正在做的那樣。

一般來說,一般多態性和特定接口的目的是數據對象的客戶端 (“使用者”)不需要知道實現細節。 但是, 創建 (“生成”)對象的代碼應該能夠知道實現細節(因為它填充了對象)。 因此,讓對象創建代碼知道它正在創建ArrayListLinkedList或其他任何東西都應該沒有問題。

實例化“參數化”List實現的唯一方法是通過反射,但是你肯定是通過返回List接口而不是復雜類來做正確的第一步。 一些可行的想法:

  1. 編寫一個像newList()這樣的私有方法,它只返回一個空的List實現。 在整個類中使用它,然后如果要將它從ArrayList更改為LinkedList,則只需更改該newList()方法的實現。 這與您的getSpecificList()方法類似
  2. 如果您希望客戶端選擇List實現:在構造函數中接受List類:

    public MyClass(Class <?extends List <T >>){...}

想法#2需要反射來實例化List實現,但這可能不是你想要的。

如果列表中的“數組”或“鏈接”部分對您的實現很重要,那么將其公開。 如果不重要,那就不要了。

可以有一個像這樣的界面:

 ArrayList<T> createArrayList();

如果由於某種原因,List的實施很重要。 當您需要的只是List-ishness時,返回“List”是一種很好的做法,在這種情況下,實現不太重要。

他們理解你的問題(我可能會誤解;你的問題不是很清楚),你只是在搜索通用方法的正確語法 - 它看起來像這樣:

public <T> List<T> getSpecificList()
{
    return new ArrayList<T>();
}

- 注意前導<T> 現在,如果要更改列表的類型,則此更改僅限於一個位置。

如果您沒有初始化myList,那么您只需要在一個位置更改內容。 除非您當然需要使用ArrayList獨有的任何方法...

List<AnyType> myList = getSpecicList();

public List<AnyType> getSpecificList()
{
    return new ArrayList<AnyType>();
}

這個怎么樣?

public class MyClass<T>
{
    List<T> myList = this.getSpecificList();

    public List<T> getSpecificList()
    {
        return new ArrayList<T>();
    }
}

現在您只需要在一個地方更改類型。

暫無
暫無

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

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