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泛型类指定多个泛型