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

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

java泛型类指定多个泛型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338387.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python大型项目经验_图像分类:13个Kaggle项目的经验总结

来源&#xff1a;数据派THU任何领域的成功都可以归结为一套小规则和基本原则&#xff0c;当它们结合在一起时会产生伟大的结果。机器学习和图像分类也不例外&#xff0c;工程师们可以通过参加像Kaggle这样的竞赛来展示最佳实践。在这篇文章中&#xff0c;我将给你很多资源来学习…

C语言程序main入口函数

一.main()函数是什么样的我们先要搞清楚main()函数有哪几种&#xff1f;查阅C89/C99/C11标准文档&#xff0c;里面明确固定了两种写法&#xff1a;int main(void) { /* ... */ }int main(int argc, char *argv[]) { /* ... */ }除此之外&#xff0c;其他写法应该都是不规范的写…

spring可用于数据层吗_Spring XD用于数据提取

spring可用于数据层吗Spring XD是一个功能强大的工具&#xff0c;它是一组可安装的Spring Boot服务&#xff0c;可以独立运行&#xff0c;在YARN或EC2之上运行。 Spring XD还包括一个管理UI网站和一个用于作业和流管理的命令行工具。 Spring XD是一组功能强大的服务&#xff0c…

go语言mysql操作_使用Go语言操作MySQL数据库的思路与步骤

最近在做注册登录服务时&#xff0c;学习用Go语言操作MySQL数据库实现用户数据的增删改查&#xff0c;现将个人学习心得总结如下&#xff0c;另外附有代码仓库地址&#xff0c;欢迎各位有兴趣的fork。软件环境&#xff1a;Goland、Navicat for MySQL。一、实现思路1&#xff0c…

学习嵌入式C语言的6个层级,你在哪一层?

C语言可以说是一种经典的编程语言&#xff0c;没有C语言就没有今天的各种操作系统。C语言是基础&#xff0c;那么你掌握了多少&#xff1f;新手级别学习目的&#xff1a;过计算机二级&#xff0c;考证&#xff0c;应付期末考试。需要掌握的程度&#xff1a;掌握C语言的基本语法…

intellij idea_IntelliJ IDEA内部设计

intellij ideaIntelliJ IDEA的第一个版本于2001年1月发布&#xff0c;当时它是第一个集成了高级代码导航和代码重构功能的Java IDE之一。 2009年&#xff0c;JetBrains开源了其社区版本 。 从那时起&#xff0c;创建了许多基于它的IDE&#xff0c;例如Google的Android Studio。…

mysql索引下沉_MySQL 5.6 索引条件下推优化

索引下推优化是MySQL5.6版本中新加的功能。索引条件下推(ICP)是对MySQL使用索引从表中检索行的情况的优化。如果没有ICP&#xff0c;存储引擎会遍历索引以查找基表中的行&#xff0c;并将它们返回给MySQL服务器&#xff0c;由server层再做一波筛选。启用ICP后&#xff0c;如果只…

C语言 | 函数执行成功时,return 1 还是return 0?

今天分享的内容是关于函数执行成功&#xff0c;返回0还是1的讨论~基本上&#xff0c;没有人会将大段的C语言代码全部塞入 main() 函数&#xff0c;更好的做法是按照复用率高&#xff0c;耦合性低的原则&#xff0c;尽可能的将代码拆分不同的功能模块&#xff0c;并封装成函数。…

jcache_窥探JCache API(JSR 107)

jcache这篇文章从较高的层次介绍了JCache API&#xff0c;并提供了一个预告片–仅够您&#xff08;希望&#xff09;开始对此发痒了&#xff1b;-) 在这篇文章中……。 JCache概述 JCache API&#xff0c;实现 JCache API支持的&#xff08;Java&#xff09;平台 快速了解O…

redis 启动加载mysql_Redis分析系列:启动加载过程

从本篇文章开始(命名为Redis分析系列)&#xff0c;将会通过分析Redis的源代码(以Redis 2.2.0 RC1为准)&#xff0c;来对它的内部实现做一些探讨。本文主要介绍Redis启动加载过程&#xff0c;总体上可以分为如下几步&#xff1a;1. 初始化全局服务器配置2. 加载配置文件(如果指定…

c 文件怎么进行读取和写入操作?

C >>和<<读写文本文件&#xff1a;fstream 或者 ifstream 类负责实现对文件的读取&#xff0c;它们内部都对 >> 输出流运算符做了重载&#xff1b;同样&#xff0c;fstream 和 ofstream 类负责实现对文件的写入&#xff0c;它们的内部也都对 << 输出流…

mysql+误操作怎么恢复_Mysql误操作恢复流程

一、开启binlog。show variables like log_bin;#vim /etc/my.cnf在[mysqld]中加入log-bin mysql-binlog-bin /usr/local/mysql/log/mysql-bin.log重启mysql服务#service mysqld stop#service mysqld start二、数据写入建库create database …

drools6.5_Drools 6.2.0.Final发布

drools6.5我们很高兴地宣布最新&#xff0c;最出色的Drools 6.2.0.Final版本。 特别是此发行版更加注重改进的可用性和功能&#xff0c;这些功能使项目更易于使用&#xff08;和采用&#xff09;。 新功能包括对工作台UI的大量改进&#xff0c;对社交活动和插件管理的支持以及…

c程序编写x的y次方的方法

c程序怎么编写x的y次方?C语言pow()函数&#xff1a;求x的y次方&#xff08;次幂&#xff09;头文件&#xff1a;#include pow() 函数用来求 x 的 y 次幂&#xff08;次方&#xff09;&#xff0c;其原型为&#xff1a;double pow(double x, double y);pow()用来计算以x 为底的…

python redis pipeline使用方法_python使用pipeline批量读写redis的方法

用了很久的redis了。随着业务的要求越来越高。对redis的读写速度要求也越来越高。正好最近有个需求(需要在秒级取值1000的数据)&#xff0c;如果对于传统的单词取值&#xff0c;循环取值&#xff0c;消耗实在是大&#xff0c;有小伙伴可能考虑到多线程&#xff0c;但这并不是最…

jboss fuse 教程_JBoss Fuse –一些鲜为人知的技巧

jboss fuse 教程TL; DR 将Java静态调用公开为Karaf Shell本机命令 在部署时覆盖OSGi标头 在使用OSGi片段部署时间后覆盖OSGi标头 将Java静态调用公开为Karaf Shell本机命令 作为必须与支持人员和客户进行协作的软件工程师的一部分&#xff0c;我经常发现自己需要从无法访问…

8条嵌入式C语言编程小知识总结

1. 流水线被指令填满时才能发挥最大效能&#xff0c;即每时钟周期完成一条指令的执行(仅指单周期指令)。如果程序发生跳转&#xff0c;流水线会被清空&#xff0c;这将需要几个时钟才能使流水线再次填满。因此&#xff0c;尽量少的使用跳转指令可以提高程序执行效率&#xff0c…

c语言函数的三种调用方式是什么?

函数的三种调用方式&#xff1a;1、函数作为表达式中的一项出现在表达式中&#xff0c;例“zmax(x,y)”&#xff1b;2、函数作为一个单独的语句&#xff0c;例“printf("%d",a)”&#xff1b;3、函数作为调用另一个函数时的实参&#xff0c;例“printf("%d"…

CF1913D. Array Collapse [dp+单调栈+前缀和]

传送门 [前题提要]:感觉dp还是很显然的,感觉单调栈也不是很难想,但是VP的时候脑子比较乱,dp方程想偏了,没写出来… 看完题目,不难发现应该存在一种递推关系.因为会发现最后剩下来的必然是原序列的一种子序列,然后这种子序列计数的问题.应该想到使用dp计数. 刚开始我的想法是使…

弱口令扫描工具mysql ftp_基于端口的弱口令检测工具--iscan

iscan: 基于端口的弱口令检测工具亲手打造了一款基于端口的弱口令检测工具&#xff0c;使用python进行编写&#xff0c;主要可以用于渗透测试中常见服务端口弱口令的检测。目前支持以下服务&#xff1a;系统弱口令&#xff1a;ftp、ssh、telnet、ipc$数据库弱口令&#xff1a;m…