java多态和泛型_Java泛型中的多态

java多态和泛型

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.add(new Dog())代码,即使ALIST是猫名单的类型,这是错误的! 我们不能将Dog对象添加到Cat列表中,因为该列表仅声明为具有Cat对象(或其子类)。 泛型可以使列表类型安全并且在技术上有意义。 为了接受多态子/超类,我们可以使用通配符来增强方法签名,这可以在另一个会话中进行讨论。

翻译自: https://www.javacodegeeks.com/2015/03/polymorphism-in-java-generics.html

java多态和泛型

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值