Java泛型中的多态
從作為Java程序員的早期開始,我們都知道如何實例化和使用Collection對象。 實例化為具體類的List接口將如下所示。
List myArrayList = new ArrayList();如果myArrayList應該僅保存Integer對象,則從Java 5編譯器開始,按照Java Generics規范,實例化將如下所示:
List<Integer> myArrayList = new ArrayList<Integer>();在同一行中,接受和/或返回字符串列表的方法將從
public List processStrings(ArrayList myStringList);至
public List<String> processStrings(ArrayList<String> myStringList);而且它們是類型安全的,因此我們不必進行強制轉換即可檢索列表對象的項目
String aStringFromMyStringList = myStringList.get(0); //No ClassCastException possible.如果將aStringFromMyStringList聲明為String以外的任何內容,則以上內容將不會編譯。
到這里為止,我們應該對面向對象的Java如何工作感到滿意,但是下一項可能會讓很多人感到驚訝。
當我們使用List<Integer> myArrayList = new ArrayList<Integer>(); 意味著我們應該只在ArrayList和NOTHING ELSE中使用“ Integer”。 等一下,泛型不是OOP的一部分,這意味著我們不能在這些對象中應用多態嗎? 答案是不。 讓我們看看為什么。
我們已經看到多態性適用于集合的基本類型,這就是為什么List<Integer> myArrayList可以實例化為新的ArrayList<Integer>();
但是呢:
class Parent{}class Child extends Parent{}使用以上方法,以下實例將無法正常工作,并最終導致編譯錯誤。
List<Parent> myList = new ArrayList<Child>() //Compilation Error;一個簡單的規則是變量聲明的類型必須與您傳遞給實際對象類型的類型相匹配。 如果我們聲明List<Parent> myList那么我分配給myList任何myList必須僅是<Parent>類型,而不是Parent類的子類型,而不是Parent類的超類型。
這意味著正確的代碼是:
List<Parent> myList = new ArrayList<Parent>(); // Compiles fine但是以上內容與習慣于使用以下合法內容的傳統Java程序員矛盾。
Parent[] myParentArray = new Child[10];要詳細了解上述差異,讓我們有一個如下的繼承結構:
public class Animal{}public class Cat extends Animal{}public class Dog extends Animal{}我們可以在數組中實現多態,因為不應將數組指定為安全類型。 請參見下面的數組示例,以及為什么我們需要將類型安全列表作為Collection對象。
public void addAnimals(Animal[] animals ) {animals [0] = new Animal();// If passed animal[] is of type Dog[] then we are adding a Cat object to a Dog[] array.animals [1] = new Cat();// If passed animal[] is of type Cat[] then we are adding a Dog object to a cat[] array.animals [1] = new Dog(); }由于貓或狗是動物的類型,因此可以將貓陣列或狗陣列作為動物陣列進行傳遞。
public class callerClass() {Animal[] animalArray = new Animal[10];Cat[] catArray = new Cat[10];Dog[] dogArray = new Dog[10];addAnimals(animalArray); //Expected, no questions raised here. addAnimals(catArray); //As Cat[] is a type of Animal[] so we may end up in adding a Cat in Dog Array. addAnimals(dogArray); // As Dog[] is a type of Animal[] so if Cat[] is passed we may end up in adding a Dog in a //Cat array. }但是看看如果我們使用Collections會發生什么。 我們可以有類似上面的方法:
public void addAnimals(List<Animal> myAnimalList()) { //Some code here. }調用上述方法的調用方方法如下所示。
public class callerClass() {List<Animal> animalList = new ArrayList<Animal>();List<Cat> catList = new ArrayList<Cat>();List<Dog> dogList = new ArrayList<Dog>();addAnimals(animalList); addAnimals(catList);addAnimals(dogList); }如果我們嘗試編譯以上內容,會發生什么? 它將在addAnimals(catList);行失敗addAnimals(catList); 和addAnimals(dogList) ,因為List類型與addAnimals(List<Animal> myAnimalList())方法的預期列表類型不匹配。 該方法期望列表僅聲明為動物類型。
盡管上面的方法失敗了,但是當列表被聲明為超類型列表時,泛型實際上可以保留子類型的實例。 例如,我們可以像下面這樣詳細實現addAnimals( List<Animal> myAnimalList () myAnimalList List<Animal> myAnimalList () )方法。
public void addAnimals(List<Animal> myAnimalList ()) {aList.add(new Animal()); // Expected code.aList.add(new Cat()); //Yes this works.aList.add(new Dog()); //Any Animal subtype works. }這意味著我們可以將子超類繼承概念應用到對象列表中,而不是將對象作為方法參數分配或傳遞給列表。
這就是Java禁止編譯addAnimals(catList)代碼的原因,因為如果編譯了該代碼,則稍后在已實現的addAnimals方法中,即使aList是一個aList,也始終可以使用aList.add(new Dog())代碼。貓名單的類型,這是錯誤的! 我們不能將Dog對象添加到Cat列表中,因為該列表僅聲明為具有Cat對象(或其子類)。 泛型可以使列表類型安全并且在技術上有意義。 為了接受多態子/超類,我們可以使用通配符來增強方法簽名,這可以在另一個會話中進行討論。
翻譯自: https://www.javacodegeeks.com/2015/03/polymorphism-in-java-generics.html
總結
以上是生活随笔為你收集整理的Java泛型中的多态的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 郭明錤:华为归来对消费者来说是好事,倒逼
- 下一篇: 苹果电脑页面关闭快捷键(苹果电脑强制关闭