java 泛型嵌套泛型_Java泛型简介–第6部分

java 泛型嵌套泛型

这是关于泛型的介绍性讨论的延续, 此处的先前部分可以在此处找到。

在上一篇文章中,我们讨论了关于类型参数的递归边界。 我们看到了递归绑定如何帮助我们重用了车辆比较逻辑。 在该文章的结尾,我建议当我们不够谨慎时,可能会发生类型混合。 今天我们将看到一个例子。

如果有人错误地通过以下方式创建了Vehicle的子类,则可能会发生混合:

/*** Definition of Vehicle*/
public abstract class Vehicle<E extends Vehicle<E>> implements Comparable<E> {// other methods and propertiespublic int compareTo(E vehicle) {// method implementation}
}/*** Definition of Bus*/
public class Bus extends Vehicle<Bus> {}/*** BiCycle, new subtype of Vehicle*/
public class BiCycle extends Vehicle<Bus> {}/*** Now this class’s compareTo method will take a Bus type* as its argument. As a result, you will not be able to compare* a BiCycle with another Bicycle, but with a Bus.*/
cycle.compareTo(anotherCycle);  // This will generate a compile time error
cycle.compareTo(bus);    // but you will be able to do this without any error

枚举不会发生这种类型的混淆,因为JVM负责子类化和为枚举类型创建实例,但是如果我们在代码中使用这种样式,则必须小心。

让我们谈谈递归边界的另一个有趣的应用。 考虑以下类别:

public class MyClass {private String attrib1;private String attrib2;private String attrib3;private String attrib4;private String attrib5;public MyClass() {}public String getAttrib1() {return attrib1;}public void setAttrib1(String attrib1) {this.attrib1 = attrib1;}public String getAttrib2() {return attrib2;}public void setAttrib2(String attrib2) {this.attrib2 = attrib2;}public String getAttrib3() {return attrib3;}public void setAttrib3(String attrib3) {this.attrib3 = attrib3;}public String getAttrib4() {return attrib4;}public void setAttrib4(String attrib4) {this.attrib4 = attrib4;}public String getAttrib5() {return attrib5;}public void setAttrib5(String attrib5) {this.attrib5 = attrib5;}
}

如果我们要创建此类的实例,则可以执行以下操作:

MyClass mc = new MyClass();
mc.setAttrib1("Attribute 1");
mc.setAttrib2("Attribute 2");

上面的代码创建该类的实例并初始化属性。 如果我们可以在此处使用方法链接 ,那么我们可以编写:

MyClass mc = new MyClass().setAttrib1("Attribute 1").setAttrib2("Attribute 2");

显然比第一个版本好得多。 但是,要启用这种方法链接,我们需要通过以下方式修改MyClass

public class MyClass {private String attrib1;private String attrib2;private String attrib3;private String attrib4;private String attrib5;public MyClass() {}public String getAttrib1() {return attrib1;}public MyClass setAttrib1(String attrib1) {this.attrib1 = attrib1;return this;}public String getAttrib2() {return attrib2;}public MyClass setAttrib2(String attrib2) {this.attrib2 = attrib2;return this;}public String getAttrib3() {return attrib3;}public MyClass setAttrib3(String attrib3) {this.attrib3 = attrib3;return this;}public String getAttrib4() {return attrib4;}public MyClass setAttrib4(String attrib4) {this.attrib4 = attrib4;return this;}public String getAttrib5() {return attrib5;}public MyClass setAttrib5(String attrib5) {this.attrib5 = attrib5;return this;}
}

然后我们将可以对此类的实例使用方法链接。 但是,如果我们想在涉及继承的地方使用方法链接,那么事情就会变得混乱:

public abstract class Parent {private String attrib1;private String attrib2;private String attrib3;private String attrib4;private String attrib5;public Parent() {}public String getAttrib1() {return attrib1;}public Parent setAttrib1(String attrib1) {this.attrib1 = attrib1;return this;}public String getAttrib2() {return attrib2;}public Parent setAttrib2(String attrib2) {this.attrib2 = attrib2;return this;}public String getAttrib3() {return attrib3;}public Parent setAttrib3(String attrib3) {this.attrib3 = attrib3;return this;}public String getAttrib4() {return attrib4;}public Parent setAttrib4(String attrib4) {this.attrib4 = attrib4;return this;}public String getAttrib5() {return attrib5;}public Parent setAttrib5(String attrib5) {this.attrib5 = attrib5;return this;}
}public class Child extends Parent {private String attrib6;private String attrib7;public Child() {}public String getAttrib6() {return attrib6;}public Child setAttrib6(String attrib6) {this.attrib6 = attrib6;return this;}public String getAttrib7() {return attrib7;}public Child setAttrib7(String attrib7) {this.attrib7 = attrib7;return this;}
}/*** Now try using method chaining for instances of Child* in the following way, you will get compile time errors.*/
Child c = new Child().setAttrib1("Attribute 1").setAttrib6("Attribute 6");

这样做的原因是,即使Child从其父级继承了所有的setter,所有这些setter方法的返回类型也都是Parent类型,而不是Child类型。 因此,第一个设置器将返回类型为Parent的引用,调用setAttrib6会导致编译错误,因为它没有任何此类方法。

我们可以通过在Parent上引入通用类型参数并在其上定义递归绑定来解决此问题。 它的所有子项从其扩展时都将自己作为类型参数传递,从而确保setter方法将返回其类型的引用:

public abstract class Parent<T extends Parent<T>> {private String attrib1;private String attrib2;private String attrib3;private String attrib4;private String attrib5;public Parent() {}public String getAttrib1() {return attrib1;}@SuppressWarnings("unchecked")public T setAttrib1(String attrib1) {this.attrib1 = attrib1;return (T) this;}public String getAttrib2() {return attrib2;}@SuppressWarnings("unchecked")public T setAttrib2(String attrib2) {this.attrib2 = attrib2;return (T) this;}public String getAttrib3() {return attrib3;}@SuppressWarnings("unchecked")public T setAttrib3(String attrib3) {this.attrib3 = attrib3;return (T) this;}public String getAttrib4() {return attrib4;}@SuppressWarnings("unchecked")public T setAttrib4(String attrib4) {this.attrib4 = attrib4;return (T) this;}public String getAttrib5() {return attrib5;}@SuppressWarnings("unchecked")public T setAttrib5(String attrib5) {this.attrib5 = attrib5;return (T) this;}
}public class Child extends Parent<Child> {private String attrib6;private String attrib7;public String getAttrib6() {return attrib6;}public Child setAttrib6(String attrib6) {this.attrib6 = attrib6;return this;}public String getAttrib7() {return attrib7;}public Child setAttrib7(String attrib7) {this.attrib7 = attrib7;return this;}
}

请注意,我们已经明确地施放T类型,因为编译器不知道这种转换是否是可能的,即使它是因为牛逼的定义是由父<T>界。 同样,由于我们将对象引用转换为T ,因此编译器将发出未经检查的警告。 为了抑制这种情况,我们在设置器上方使用了@SuppressWarnings(“ unchecked”)

经过上述修改,这样做是完全有效的:

Child c = new Child().setAttrib1("Attribute 1").setAttrib6("Attribute 6");

当以这种方式编写方法设置器时,我们应注意不要将递归边界用于其他任何目的,例如从父级访问子级状态,因为这会使父级暴露于其子类的内部细节,并最终破坏封装。

通过这篇文章,我完成了泛型的基本介绍。 我在本系列中没有讨论太多的事情,因为我认为它们已经超出了介绍的范围。

直到下一次。

翻译自: https://www.javacodegeeks.com/2014/07/an-introduction-to-generics-in-java-part-6.html

java 泛型嵌套泛型

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

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

相关文章

优化自定义函数_Pandas常见的性能优化方法

文章来源于Datawhale &#xff0c;作者阿水Pandas是数据科学和数据竞赛中常见的库&#xff0c;我们使用Pandas可以进行快速读取数据、分析数据、构造特征。但Pandas在使用上有一些技巧和需要注意的地方&#xff0c;如果你没有合适的使用&#xff0c;那么Pandas可能运行速度非常…

pycharm cant open file_PyCharm

1.创建项目PyCharm是一种Python IDE.PyCharm的功能到底有多强大&#xff0c;我也说不清楚&#xff0c;今天只是介绍一下关于Pycharm创建项目的问题.✦ PyCharm可以将一个文件夹作为工程(或项目)进行打开.如图1所示&#xff0c;先创建两个文件夹(pyc1和pyc2)&#xff0c;在文件夹…

adminlte支持html5吗,spring boot:用adminlte做前端

标签(空格分隔)&#xff1a; sringboot adminlte thymeleafspring boot 和 adminlte没有紧密的联系&#xff0c;只是最近在做的一个东西用spring boot做后端用adminlte做前端&#xff0c;所以就放到spring boot系列里面讲。架构原理adminlte只是一个库&#xff0c;说不上什么框…

如何通过示例使用Java中的Exchanger

大家好&#xff0c;如果您在并发Java应用程序中工作&#xff0c;那么您可能听说过java.util.concurrent包的Exchanger类。 Java中的Exchanger是Java 1.5中与CountDownLatch &#xff0c; CyclicBarrier和Semaphores一起引入的另一个并发或同步实用程序。 顾名思义&#xff0c; …

python里写在文件的指定行_python文件操作如何写在指定的行

常常在操作文件时我们只想在某一行的插入信息&#xff0c;可以先将文件读入列表中&#xff0c;利用列表的下标插入文本&#xff0c;之后再重新写入文件。但是弊端是&#xff0c;如果文件量太大列表的性能可能不是很高。python代码&#xff1a;#codingutf-8lines[]fopen("d…

外星人跑深度学习_上海港汇外星人店,51M2020开光追和DLSS2.0畅玩《赛博朋克2077》...

上海外星人港汇恒隆广场店是外星人布局上海的首家3.0店面&#xff0c;坐落在繁华的徐家汇商圈港汇恒隆广场南座6楼。门店传承了外星人高端高品质&#xff0c;以服务客户为宗旨&#xff0c;立足上海&#xff0c;辐射周边&#xff0c;服务所有外星人客户。近日&#xff0c;让全球…

python flask html模板,python flask web开发实战 Jinja2模板

templates/index.htmlHello World!templates/user.htmlHello, {{ name }}!渲染模板&#xff1a;from flask import Flask,render_templateapp.route(/)def index():return render_template(index.html)app.route(/user/)def user(name):return render_template(user.html, name…

gwt前台开发_为GWT设置开发环境

gwt前台开发介绍 这是旨在用Java开发跨平台移动应用程序的系列文章的一部分 。 在此博客文章中&#xff0c;我们将了解GWT是什么&#xff0c;并为GWT设置开发环境。 GWT是一个开源开发工具包&#xff0c;用于开发基于浏览器的复杂Ajax应用程序。 使用GWT&#xff0c;您可以用J…

linux 释放进程res_linux内存查看及释放

查看内存常用的查看内存工具有&#xff1a;top&#xff0c;ps&#xff0c;free&#xff0c;/proc/meminfo&#xff0c;/proc/$PID/status等&#xff0c;一般都指定了虚拟内存占用情况&#xff0c;但ps或/proc/$PID/status中RSS或RSZ指定的是实际内存大小。1)freeroot:~# freeto…

js读取外部json指定字段值完整代码_前端工程化 剖析npm的包管理机制(完整版)...

导读 现如今&#xff0c;前端开发的同学已经离不开 npm 这个包管理工具&#xff0c;其优秀的包版本管理机制承载了整个繁荣发展的NodeJS社区&#xff0c;理解其内部机制非常有利于加深我们对模块开发的理解、各项前端工程化的配置以加快我们排查问题(相信不少同学收到过各种依赖…

计算机专业带给我们的启示,一次电脑网络调查带给我的启示

一次电脑网络调查带给我的启示当今世界&#xff0c;鲜有人不会上网。而许多孩子&#xff0c;也迷上了电脑。就此&#xff0c;我对周围的12个朋友做了调查。其中3人上网玩QQ&#xff0c;8人玩摩尔庄园&#xff0c;仅1人玩单机游戏。很显然&#xff0c;网络已深入孩子们的生活。做…

Apache Derby数据库JVM安全策略

抽象 我已经发布了许多有关Derby的博客&#xff1a; Derby数据库备份 同一主机上的多个Derby网络服务器 Apache Derby数据库用户和权限 与Maven和内存中Derby数据库的集成测试 这本不打算是一个系列。 但是多年来&#xff0c;我越来越多地使用Derby。 我开始使用Derby作为…

大师兄科研网vasp_怎样知道一名研究生有没有科研潜力?

原答案回答在这里了。怎么知道一名研究生有没有科研潜力&#xff1f;​www.zhihu.com大家熟悉的“员工执行力”这个词&#xff0c;其实是个伪命题&#xff0c;因为员工的执行力&#xff1d;领导的领导能力&#xff0c;领导方法得当&#xff0c;每个人都有很强的执行力。那么“学…

西交计算机专业912一样吗,西安交大912(总分404 专业课133分)经验总结

2019年西交912计算机基础经验总结(总分404 政治&#xff1a;68 英语二&#xff1a;84 数学二&#xff1a;119 专业课&#xff1a;133)先说一下个人情况吧。本人2017年毕业于西安电子科技大学计算机科学与技术专业&#xff0c;毕业以后就职于一家国企&#xff0c;奈何不安分&…

分行打印列表python_#python版一行内容分行输出

python版一行内容分行输出 1.[代码][Python]代码236091543 #python版一行内容分行输出 #依山居 18:14 2015/11/4 #题目来源 http://www.bathome.net/thread-1454-1-1.html a="aA1一bB2二cC3三dD4四eE5五fF6六gG7七hH8八iI9九" """ 分行输出为: abcdef…

机箱硬盘指示灯不亮_安钛克DF600 FLUX机箱:FLUX平台第一款机箱,为全民电竞热“降温”...

随着夏天的到来&#xff0c;电脑对散热的要求越来越高&#xff0c;特别是对于希望游戏的电竞玩家&#xff0c;不久前China Joy全球电竞大会的落幕&#xff0c;“全民电竞”这个概念再一次深入人心&#xff0c;而一名电脑主机电竞玩家&#xff0c;势必需要一款散热效果更好的机箱…

java ee maven_针对新手的Java EE7和Maven项目–第7部分

java ee maven从前面的部分恢复 第1 部分 &#xff0c; 第2 部分 &#xff0c; 第3 部分 &#xff0c; 第4 部分 &#xff0c; 第5 部分 &#xff0c; 第6部分 在上一篇文章&#xff08;第6章&#xff09;中&#xff0c;我们发现了如何使用Arquillian和Wildfly 8.1进行JPA2域模…

法在计算机课程中的应用,任务驱动法在计算机办公课程中的应用

摘 要&#xff1a;一体化教学模式中的任务驱动法是建立在建构主义教育理论基础上的一种教学法。笔者结合任务驱动法在Word2010教学中的实施过程&#xff0c;对如何应用任务驱动法展开论述。关键词&#xff1a;任务驱动法 计算机办公课程 具体应用任务驱动法就是在教学过程中&am…

链表node中保存的是什么_Redis源码解析一 --链表结构

Redis源码剖析—链表结构1. redis中的链表在redis中链表的应用非常广泛&#xff0c;例如列表键的底层实现之一就是链表。而且&#xff0c;在redis中的链表结构被实现成为双向链表&#xff0c;因此&#xff0c;在头部和尾部进行的操作就会非常快。通过列表键的命令感受一下双向链…

python数据分析方法和命令_《利用Python进行数据分析》 —— (1)

《利用Python进行数据分析》 —— &#xff08;1&#xff09; Python的学习需要自主探索各种类型&#xff0c;函数和方法的文档。 2.1 Python解释器 在IPython&#xff08;Jupyter Qtconsole)上&#xff0c;可以通过%run命令执行文件中的代码 In [16]: %run hellow.py 1,2,3 10…