写点什么

新 JEP 将简化 Java 类型变异

  • 2017-02-06
  • 本文字数:2073 字

    阅读完需:约 7 分钟

新的JEP Candidate 旨在简化处理Java 中复杂的类型变异的概念。这个新的JEP Candidate 可能会在Java 10 中推出,提供了在定义的泛型类型中指定目标对象默认变异的方法,而不是在泛型类型实例化时通过通配符指定。这个新方案并不会代替通配符,而是减少对通配符的需求。

类型变异这个概念对于很多开发人员来说仍然比较模糊,在Java 中通过不太普及的通配符来解决这个问题并没有很大帮助。因此,为了帮助我们的读者能够理解这款JEP 的潜在影响力,在本文中我们将首先解释什么是类型变异,目前Java 中是怎么解决它的,之后将介绍这个新方案能实现什么。

变异、协变和逆变

以下的代码属于传统的在线购物应用程序:

复制代码
public class Product {
/* ... */
}
public class FrozenProduct extends Product {
/* ... */
}

如果有个方法 scan(Product product),我们调用它传递 FrozenProduct 对象,调用工作没有问题,这是众所周知的多态性的一般规则。但是当参数中包含泛型时,就不能使用相同的逻辑,以下的代码将无法编译:

复制代码
private void addAllProducts(List<Product> products) {
/* Check product stock */
shoppingCart.addAll(products);
}
private void freezerSection() {
List<FrozenProduct> frozenProducts = /* select frozen products */;
addAllProducts(frozenProducts); // ERROR: List<Product> expected
// List<FrozenProduct> found
}

当在 Java 中使用泛型时,并没有关于目标类型和其子类型或超类型之间兼容性的假设。换句话说,当使用泛型时,我们默认目标类型是不变的,它只接受明确的类型。

然而,在上面的例子中,我们可以看到 addAllProducts 方法可以处理 List of Product 或是其子类型。当泛型参数可以接受其目标类型或是它的任何子类型,我们就说这个类型是协变的,在 Java 中可以用 extends 表示:

复制代码
private void addAllProducts(List<? extends Product> products) {
/* Check product stock */
shoppingCart.addAll(products);
}
private void freezerSection() {
List<FrozenProduct> frozenProducts = /* select frozen products */;
addAllProducts(frozenProducts); // works with no problem
}

在这些例子中,接受的目标类型的变异是子类型。在一些其他例子中,目标类型的变异不是子类型,而是超类型。考虑以下的情况:

复制代码
private boolean askQuestion(Predicate<String> p) {
return p.test("hello");
}
private void applyPredicate() {
Predicate<Object> evenLength = o -> o.toString().length() % 2 == 0;
askQuestion(evenLength); // ERROR: Predicate<String> expected
// Predicate<Object> found
}

在这种情况下,我们可以看到使用 string “hello”到 lambda o -> o.toString().length() % 2 == 0 中不会发生问题,然而,编译器不允许我们这么做。askQuestion 可以处理 Predicate of String 或其任意超类型:我们就说这种情况下的目标类型是逆变的,在 Java 中可以用 super 表示:

复制代码
private boolean askQuestion(Predicate<? super String> p) {
return p.test("hello");
}
private void applyPredicate() {
Predicate<Object> evenLength = o -> o.toString().length() % 2 == 0;
askQuestion(evenLength); // works with no problem
}

通配符是创建类型变异的一种非常灵活的方法,因为它允许你在不同地方对同种类型定义不同的变异。比如说,在上面的例子里我们定义 addAllProducts 是协变的参数,但在其他地方根据我们的需求,可以定义它为逆变或是不变的。然而缺点是必须在每个地方根据需要明确指定变异,这样会造成很多的冗余和混乱。所以新的方案应运而生。

在声明时指定默认变异

通配符的最主要的问题是它们比开发人员通常需要的还要灵活。在Predicate<String>的例子中,我们理论上可以创建一个方法Predicate<? extends String>,然而,可以用到的用例有限(可能根本没有)。在大量情况下,只有一个类型变异有意义,为了反映出这一点, JEP 300 提供了在声明泛型类型时指定默认变异的方法,而不是在实例化时指定默认变异。比如说,用了这种方案,可以使用逆变的关键字Predicate<contravariant T>来重写接口Predicate<T>,这就代表着任何时候开发人员写Predicate<String>都会被隐含地理解为Predicate<? super String>

这个新功能的语法尚未决定,但是已经有了一些备选项:使用新的显式关键字,如Function<contravariant T, covariant R>,或遵循其他语言的先例,如 Scala 中的符号(Function<-T, +R>),或是 C#中的较短关键字(Function<in T, out R>)。在解决语法问题之前,还需要解决一些重要的技术问题,即默认变异和通配符之间的交互,默认变异对现有代码产生的影响,以及变异类型兼容性检查的实际机制。

最后值得提出的一点是,JEP 300 仅会处理新的默认变异,但不会修改 Java 库中可用的任何类和接口。如果之后 JEP 300 再发展可能会考虑处理这种情况,但也只是在其他版本的 JEP 中执行。

查看英文原文 New JEP Would Simplify Java Type Variance

2017-02-06 18:001857
用户头像

发布了 218 篇内容, 共 69.3 次阅读, 收获喜欢 76 次。

关注

评论

发布
暂无评论
发现更多内容

让运动自然发生,FITURE打造全新生活方式

科技热闻

Linux常用命令

五分钟学大数据

Linux 7月月更

任何时间,任何地点,超级侦探,认真办案!

龙智—DevSecOps解决方案

Jira Atlassian Jira Jira插件

微软Azure和易观分析联合发布《企业级云原生平台驱动数字化转型》报告

易观分析

数字化转型

玩游戏想记录一下自己超神的瞬间?那么就来看一下如何使用Unity截图吧

恬静的小魔龙

游戏开发 Unity 游戏引擎

2022 年中回顾|一文看懂预训练模型最新进展

澜舟孟子开源社区

人工智能 自然语言处理 算法 nlp 预训练模型

同事看了我的代码惊呼:居然是这么在Unity中用单例的

恬静的小魔龙

游戏开发 Unity 单例模式 游戏引擎

大话DevOps监控,团队如何选择监控工具?

龙智—DevSecOps解决方案

DevOps 监控 监控软件

阿里云技术专家秦隆:可靠性保障必备——云上如何进行混沌工程

阿里云弹性计算

分布式系统 混沌工程 故障演练

Java & Go 专场 | 阿里云中间件开发者线下 Meetup 开启报名

阿里巴巴云原生

Java Go 阿里云 云原生 中间件

QCon 大会广州站它来了!独家定制双肩背包等你领取!

InfoQ写作社区官方

Qcon

【IJCAI 2022】参数高效的大模型稀疏训练方法,大幅减少稀疏训练所需资源

阿里云大数据AI技术

深度学习 模型稀疏训练

JAVA编程规范之SQL 语句

源字节1号

前端开发 后端开发

擎创科技加入龙蜥社区,共建智能运维平台新生态

OpenAnolis小助手

开源 操作系统 龙蜥社区 CLA 擎创科技

浅谈低代码技术在物流管理中的应用与创新

王平

【高并发】如何实现亿级流量下的分布式限流?这些理论你必须掌握!!

冰河

并发编程 多线程 高并发 协程 异步编程

如何判断静态代码质量分析工具的性能?这五大因素必须考虑

龙智—DevSecOps解决方案

静态代码分析 代码静态分析 静态代码安全

创新突破!亚信科技助力中国移动某省完成核心账务数据库自主可控改造

亚信AntDB数据库

国产数据库

Plus版SBOM:流水线物料清单PBOM

SEAL安全

开源 软件供应链 软件物料清单 SBOM 软件供应链安全

基于Caffe ResNet-50网络实现图片分类(仅推理)的实验复现

华为云开发者联盟

人工智能 推理 昇腾 处理器

活动报名 | 玩转 Kubernetes 容器服务提高班正式开营!

阿里巴巴云原生

阿里云 容器 云原生 训练营 课程

银行理财子公司蓄力布局A股;现金管理类理财产品整改加速

易观分析

金融 银行

Java编程程序员怎么开发水平?

小谷哥

中文起,Python 字体反爬实战案例,再一点

梦想橡皮擦

Python 爬虫 7月月更

只知道预制体是用来生成物体的?看我如何使用Unity生成UI预制体

恬静的小魔龙

游戏开发 Unity 游戏引擎

常见WEB攻击与防御

南城FE

前端 WEB安全 7月月更

【龙智技术指南】Helix4Git简明使用手册

龙智—DevSecOps解决方案

Helix Core Helix4Git

web前端开发技术学习比较靠谱

小谷哥

游戏背包系统,“Inventory Pro插件”,研究学习-----妈妈再也不用担心我不会做背包了(Unity3D)

恬静的小魔龙

游戏开发 Unity 插件 游戏引擎

用Unity不会几个插件怎么能行?Unity各类插件及教程推荐

恬静的小魔龙

游戏开发 Unity 插件 游戏引擎

怎么才能提高自己web前端技术呢?

小谷哥

新JEP将简化Java类型变异_Java_Abraham Marín Pérez_InfoQ精选文章