将亚型多态性与通用多态性相关联的危险

Java 5已将通用多态性引入Java生态系统。 即使我们都知道由于泛型类型擦除及其后果而引起的无数警告,这对Java语言还是一个很大的补充。 通用多态性(也称为参数多态性 )通常与可能预先存在的亚型多态性正交。 一个简单的例子是collections API

List<? extends Number> c = new ArrayList<Integer>();

在上面的示例中,子类型ArrayList被分配给超类型List的变量。 同时,使用Integer类型对ArrayList进行参数化,可以将其分配给兼容的参数超类型? extends Number ? extends Number 。 在泛型多态性的上下文中这种子类型多态性的用法也称为协方差 ,尽管当然也可以在非泛型上下文中实现协方差。

具有通用多态性的协方差

协方差对于泛型很重要。 它允许创建复杂的类型系统。 简单的示例涉及将协方差与通用方法结合使用:

<E extends Serializable> void serialize(Collection<E> collection) {}

上面的示例接受任何Collection类型,可以在调用站点使用诸如ListArrayListSet等类型将其子类型化。 同时,仅要求调用站点上的泛型类型参数是Serializable的子类型。 即它可以是List<Integer>ArrayList<String>等。

将亚型多态性与通用多态性相关联

于是人们常常被引诱去关联两种正交类型的多态性。 此类关联的一个简单示例是将IntegerListStringSet专门IntegerList

class IntegerList extends ArrayList<Integer> {}
class StringSet extends HashSet<String> {}

这是很容易看到明确的类型的数量会爆炸,如果你开始跨越亚型和泛型类型层次的笛卡尔积,希望通过创建之类的东西更精确地专门IntegerArrayListIntegerAbstractListIntegerLinkedList等。

使相关性通用

从上面可以看出,这种关联通常会从类型层次结构中删除通用性,尽管并不需要这样做。 在以下更一般的示例中可以看出:

// AnyContainer can contain AnyObject
class AnyContainer<E extends AnyObject> {}
class AnyObject {}// PhysicalContainer contains only PhysicalObjects
class PhysicalContainer<E extends PhysicalObject>extends AnyContainer<E> {}
class PhysicalObject extends AnyObject {}// FruitContainer contains only Fruit,
// which in turn are PhysicalObjects
class FruitContainer<E extends Fruit>extends PhysicalContainer<E> {}
class Fruit extends PhysicalObject {}

上面的示例是一个典型的示例,其中诱使API设计人员将子类型多态性( Fruit extends PhysicalObject extends AnyObject )与通用多态性( <E> )相关联,同时保持通用性,从而允许在FruitContainer添加其他子类型。 AnyObjectAnyObject应该知道其自己的子类型时,这会变得更加有趣。 这可以通过递归泛型参数来实现。 让我们修复前面的示例

// AnyContainer can contain AnyObject
class AnyContainer<E extends AnyObject<E>> {}
class AnyObject<O extends AnyObject<O>> {}// PhysicalContainer contains only PhysicalObjects
class PhysicalContainer<E extends PhysicalObject<E>>extends AnyContainer<E> {}
class PhysicalObject<O extends PhysicalObject<O>>extends AnyObject<O> {}// FruitContainer contains only Fruit,
// which in turn are PhysicalObjects
class FruitContainer<E extends Fruit<E>>extends PhysicalContainer<E> {}
class Fruit<O extends Fruit<O>>extends PhysicalObject<O> {}

这里有趣的部分不再是容器,而是AnyObject类型层次结构,该结构将子类型多态与自己类型上的通用多态相关联! 这也可以通过java.lang.Enum完成:

public class Enum<E extends Enum<E>>
implements Comparable<E> {public final int compareTo(E other) { ... }public final Class<E> getDeclaringClass() { ... }
}enum MyEnum {}// Which is syntactic sugar for:
final class MyEnum extends Enum<MyEnum> {}

危险所在?

枚举和我们的自定义之间的细微差别AnyObject层次是事实MyEnum通过被终止的两个正交分型技术递归自相关final ! 另一方面,除非将AnyObject子类型也AnyObject为最终类型,否则不应将其删除。 一个例子:

// "Dangerous"
class Apple extends Fruit<Apple> {}// "Safe"
final class Apple extends Fruit<Apple> {}

为什么final如此重要,或者换句话说,为什么在终止递归自相关(例如Apple之前)时必须小心AnyObject子类型? 这很简单。 让我们假设以下添加:

class AnyObject<O extends AnyObject<O>>implements Comparable<O> {@Overridepublic int compareTo(O other) { ... }public AnyContainer<O> container() { ... }
}

上述关于AnyObject.compareTo()约定意味着, AnyObject任何子类型只能与同一子类型进行比较。 以下是不可能的:

Fruit<?> fruit = // ...
Vegetable<?> vegetable = // ...// Compilation error!
fruit.compareTo(vegetable);

层次结构中当前唯一可比较的类型是Apple:

Apple a1 = new Apple();
Apple a2 = new Apple();a1.compareTo(a2);

但是,如果我们想添加GoldenDeliciousGala苹果怎么办?

class GoldenDelicious extends Apple {}
class Gala extends Apple {}

我们现在可以比较它们!

GoldenDelicious g1 = new GoldenDelicious();
Gala g2 = new Gala();g1.compareTo(g2);

这不是AnyObject作者的AnyObject

这同样适用于container()方法。 允许子类型协变地专门化AnyContainer类型,这很好:

class Fruit<O extends Fruit<O>>extends PhysicalObject<O> {@Overridepublic FruitContainer<O> container() { ... }
}

但是, GoldenDeliciousGalacontainer()方法会GoldenDelicious

GoldenDelicious g = new GoldenDelicious();
FruitContainer<Apple> c = g.container();

是的,它将返回一个Apple容器,而不是AnyObject设计人员想要的GoldenDelicious容器。

子类型多态和泛型多态跨越正交类型轴。 使它们相互关联可能是类型系统中的设计气味。 使它们在同一类型上关联是危险的,因为很难正确处理。 用户将尝试终止基本类型的子类型上的递归泛型类型定义。 终止的原因是具有递归自绑定的基本类型很难使用的事实。 但是终止通常会出错,因为它只能在final类上执行,而不能在常规类或接口上执行。

换句话说,如果您认为需要基于通用基类型的递归泛型类型定义,请仔细考虑,如果确实需要,并且您的类型用户可以在final类中正确终止递归泛型类型定义。

参考:来自JAVA,SQL和JOOQ博客的JCG合作伙伴 Lukas Eder提出的将子类型多态与通用多态相关联的危险 。

翻译自: https://www.javacodegeeks.com/2013/07/the-dangers-of-correlating-subtype-polymorphism-with-generic-polymorphism.html

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

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

相关文章

strtoul()要优于atoi()函数---C语言

strtoul()&#xff1a;将字符串转为长整型整数 atoi()&#xff1a;将字符串转为整型整数 在32位STM32中&#xff0c;int是32位的&#xff0c;如果字符串是“3123456789”&#xff0c;大于0x7fff fff&#xff0c;用atoi()函数返回的值就是0x7fff fff&#xff0c;而使用strtoul就…

Web前端行业的机遇与自我规划,如果你对未来没有方向 不如看一看,或许就是一道曙光!

本篇是来自西安前端开发者分享社区的经验分享&#xff0c;给出前端工作人员在行业中的发展建议&#xff0c;如果我们没有目标时候 不妨看看别人是怎么做的&#xff01; 感谢西安前端开发者分享社区的分享&#xff01; 资源下载&#xff1a;来自示说网平台&#xff08;https://…

中职升高职c语言程序设计教程课后答案,中职C语言教学创新与实践论文

中职C语言教学创新与实践论文摘要&#xff1a;自主学习体现了以学生为中心、以人为本的教学思想&#xff0c;是一种行之有效的教学方法&#xff0c;但中职学生自主学习能力整体比较欠缺&#xff0c;学生怕学、厌学现象严重&#xff0c;给教师的教学带来一定的难度。文章以C语言…

cv岗工作做什么_职场速递:我应该做什么工作?

我曾经7年换过6份工作&#xff0c;转行3次&#xff0c;只是因为一直纠结于&#xff1a;到底什么才是我想要的工作。我和很多职场人一样&#xff0c;在“我想做的&#xff0c;我喜欢的”和“我能做的&#xff0c;能养活我的”选项之间迷惘过。大部分人提起自己工作的时候&#x…

用Java和Java 8创建内部DSL,采用Martin Fowler的方法

目前&#xff0c;我正在阅读Martin Fowler撰写的有关DSL- 特定于域的语言的精彩书籍。 围绕DSL的嗡嗡声&#xff0c;围绕轻松支持DSL创建的语言&#xff0c;以及DSL的使用使我好奇地了解和了解DSL的这一概念。 到目前为止&#xff0c;这本书的使用经验令人印象深刻。 马丁福勒…

【VSCode】Windows下VSCode便携式c/c++环境

http://blog.csdn.net/c_duoduo/article/details/52083494 Ver 1.1 完整版&#xff08;修复mingw环境变量错误&#xff09;下载&#xff1a; http://pan.baidu.com/s/1jIwZcUU 转载于:https://www.cnblogs.com/shiningrise/p/8401644.html

【校招面试 之 网络】第3题 HTTP请求行、请求头、请求体详解

1、HTTP请求报文解剖 HTTP请求报文由3部分组成&#xff08;请求行请求头请求体&#xff09;&#xff1a; 下面是一个实际的请求报文&#xff1a; ①是请求方法&#xff0c;GET和POST是最常见的HTTP方法&#xff0c;除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。不过&a…

奇妙的 CSS shapes(CSS图形)

CSS 发展到今天已经越来越强大了。其语法的日新月异&#xff0c;让很多以前完成不了的事情&#xff0c;现在可以非常轻松的做到。今天就向大家介绍几个比较新的强大的 CSS 功能&#xff1a; clip-pathshape-outside shape 的意思是图形&#xff0c;CSS shapes 也就是 CSS 图形…

c++ map 多线程同时更新值 崩溃_深入理解并发安全的 sync.Map

golang中内置了map关键字&#xff0c;但是它是非线程安全的。从go 1.9开始&#xff0c;标准库加入了sync.Map&#xff0c;提供用于并发安全的map。普通map的并发问题map的并发读写代码func main() { m : make(map[int]int) go func() { for { _ m[1] // 读 } }(…

CS Academy Round #65 Count Arrays (DP)

题目链接 Count Arrays 题意 给定$n$和$m$个区间。若一个长度为$n$的$01$序列满足对于每一个给定的区间中至少有一个位置是$0$&#xff0c; 那么这个$01$序列满足条件。求有多少满足条件的$01$序列。 设$f[i]$为考虑到第$i$位的时候&#xff0c;有多少满足条件的$01$序列。 则…

c语言中栈堆,C语言中堆和栈的区别

二.堆和栈的区别1.申请方式(1)栈(satck):由系统自动分配。例如&#xff0c;声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间。(2)堆(heap):需程序员自己申请(调用malloc,realloc,calloc),并指明大小&#xff0c;并由程序员进行释放。容易产生memory leak.eg:char p;…

webview部分安卓机中文乱码

在开发过程中需要加载html片断&#xff0c;发现安卓机上是乱码&#xff0c;这可郁闷了&#xff0c;官方文档也没有这方面的介绍&#xff0c;还好度娘还好的&#xff0c;记录一下解决方案&#xff1a; 其实很简单&#xff0c;只在source对象中添一个属性baseUrl为空就可以解决&a…

MongoDB存储基础教程

一、MongoDB简介 1. mangodb是一种基于分布式、文件存储的非关系型数据库   2. C写的&#xff0c;性能高   3. 为web应用提供可扩展的高性能数据存储解决方案   4. 所支持的格式是json格式 二、MongoDB三元素&和关系型数据库的区别 三元素&#xff1a;数据库 集合(类…

Tomcat的带有守护程序和关闭挂钩的正常关闭

我的最后两个博客讨论了长时间轮询和Spring的DeferredResult技术&#xff0c;并且为了展示这些概念&#xff0c;我将我的Producer Consumer项目中的代码添加到了Web应用程序中。 尽管该代码演示了博客所提出的观点&#xff0c;但其逻辑上确实包含大量漏洞。 除了在实际的应用程…

java 递归从子节点删除父节点_LeetCode450. 删除二叉搜索树中的节点

删除一个二叉搜索树中的节点&#xff0c;需要进行情况的分类讨论&#xff0c;看一下将这个节点删除之后是否需要对二叉搜索树进行调整&#xff08;为了保持树的连接和维持二叉搜索树的性质&#xff09;。&#xff08;1&#xff09;如果删除的是一个叶子节点&#xff0c;那问题不…

1. [文件]- 文件类型,文件open模式

1.文件类型&#xff1a;文本文件和二进制文件 硬盘中的文件保存为01010101格式&#xff0c;一般读取文件是把文件从硬盘中读取到内存中。 文本文件需要进行格式转换才能读取出来。二进制文件一般用于传输二进制文件&#xff1a;视频图片 2.文件打开模式 几种不同的读取和遍历文…

c语言鼠标移动响应,CSS鼠标响应事件经过、移动、点击示例介绍

几种鼠标触发CSS事件。说明&#xff1a;onMouseDown 按下鼠标时触发onMouseOver 鼠标经过时触发onMouseUp 按下鼠标松开鼠标时触发onMouseOut 鼠标移出时触发onMouseMove 鼠标移动时触CSS 鼠标响应事件.Off{ background-color: #00FF66; padding:100px;}.up{background-color: …

node安装node-sass失败,配置淘宝源

node-sass 安装失败的原因是因为无法下载 .node 文件&#xff0c;解决办法就很简单了&#xff0c;就是我们把文件下载路径复制一份到浏览器里&#xff0c;然后使用浏览器下载文件就可以了。 具体方法 1.从node命令行中复制 .node文件下载链接并在浏览器打开下载文件https:/…

django 日志配置

django 日志配置 LOGGING { version: 1, disable_existing_loggers: False, formatters: { standard: { format: %(levelname)s %(asctime)s %(pathname)s %(filename)s %(funcName)s %(lineno)d: %(message)s }, # INFO 2016-09-03 16:25:20,067 /home/ubuntu/mysite/views.p…

带有Atomikos示例的Tomcat中的Spring JTA多个资源事务

在本教程中&#xff0c;我们将向您展示如何使用Atomikos Transaction Manager在Tomcat服务器中实现JTA多个资源事务。 Atomicos事务管理器为分布式事务提供支持。 这些是多阶段事务&#xff0c;通常使用多个数据库&#xff0c;必须以协调的方式提交。 分布式事务由XA standard描…