[英]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
的實際類型變為變量? 如果你真的想抽象出對象的創建,你應該使用一個工廠方法,就像你正在做的那樣。
一般來說,一般多態性和特定接口的目的是數據對象的客戶端 (“使用者”)不需要知道實現細節。 但是, 創建 (“生成”)對象的代碼應該能夠知道實現細節(因為它填充了對象)。 因此,讓對象創建代碼知道它正在創建ArrayList
或LinkedList
或其他任何東西都應該沒有問題。
實例化“參數化”List實現的唯一方法是通過反射,但是你肯定是通過返回List接口而不是復雜類來做正確的第一步。 一些可行的想法:
如果您希望客戶端選擇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.