从作为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泛型中的多态相关推荐

  1. 聊一聊Java 泛型中的通配符 T,E,K,V,?

    点击上方"方志朋",选择"设为星标" 回复"1024"获取独家整理的学习资料 作者:glmapper juejin.im/post/5d57 ...

  2. 聊一聊-JAVA 泛型中的通配符 T,E,K,V,?

    前言 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所操作的数据 ...

  3. Java泛型中extends T和super T的区别?

    <? extends T>和<? super T>是Java泛型中的"通配符(Wildcards)"和"边界(Bounds)"的概念. ...

  4. Java泛型中的PECS原则

    今天在写代码的时候使用到了这样一个方法签名: public void foo(Map<String, String> map); 在写这个参数的时候正好在想一些关于泛型的东西,于是: pu ...

  5. Java泛型中? 和 ? extends Object的异同分析

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 刘一手 来源 | 公众号「锅外的大佬」 Jav ...

  6. java泛型中的标记,Java泛型中的标记符含义

    Java泛型中的标记符含义: E - Element (在集合中使用,因为集合中存放的是元素) T- Type(Java 类) K- Key(键) V- Value(值) N- Number(数值类型 ...

  7. JAVA 泛型中的通配符 T,E,K,V,?

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群",加入新技术 来源:8rr.co/2Xqx 前言 Java 泛型(generic ...

  8. Java泛型中extends和super的理解(转)

    E – Element (在集合中使用,因为集合中存放的是元素) T – Type(Java 类) K – Key(键) V – Value(值) N – Number(数值类型) ? – 表示不确定 ...

  9. 一文读懂Java泛型中的通配符 ?

    之前不太明白泛型中通配符"?"的含义,直到我在网上发现了Jakob Jenkov的一篇文章,觉得很不错,所以翻译过来,大家也可以点击文末左下角的阅读原文看英文版的原文. 下面是我的 ...

最新文章

  1. Insertion Sort List
  2. 《乌合之众》读书笔记(part4)--含义最不确定的词语,往往拥有最强大的影响力
  3. 2018.11.14成立我的博客
  4. linux 下安装JDK
  5. 图像局部特征(十九)--GLOH
  6. VS2013用InstallShield生成安装包文件步骤
  7. 曼彻斯特编码_网络工程师考点集锦(数字编码和编码效率)
  8. Firefox downloadhelper 视频下载助手
  9. 单例模式中的懒汉模式和饿汉模式是什么?区别又是什么?
  10. 顶级摄影师的磨皮美白利器Portraiture,支持搭配微设证件大师使用
  11. Telegram支付接口接入
  12. 很酷的瞄准镜样式光标效果
  13. 数据分析--07:金融量化
  14. 阿拉伯数字转大写金额(支持简体和繁体)
  15. 中国机械式停车设备行业投资建议与发展机遇研究报告2022版
  16. Python可视化模块——Matplotlib(2)
  17. 【无标题】Deep AVPpred:人工智能驱动的病毒感染多肽药物的发现
  18. VMWARE虚拟机以及LINUX的详细安装教程
  19. 天津室内设计培训班:0基础必知的5个室内设计原则
  20. 噩梦中的仙境:动态规划之区间一维

热门文章

  1. mybatis简单案例源码详细【注释全面】——前期准备
  2. 定时任务---SpringBoot
  3. zookeeper出现Error contacting service. It is probably not running.
  4. FE助手 json格式化 reslet client
  5. 数据结构树的基本操作_树的各类基本操作(数据结构)
  6. groovy lambda_Java Lambda流和Groovy Clouse的比较
  7. vaadin教程_Vaadin教程
  8. hibernate查询缓存_在Hibernate中启用实体和查询缓存
  9. java 并发锁_Java并发教程–锁定:内在锁
  10. Spring Boot中的@SpringBootConfiguration注释