阿里、蚂蚁、晟腾、中科加禾精彩分享 AI 基础设施洞见,现购票可享受 9 折优惠 |AICon 了解详情
写点什么

新 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:001699
用户头像

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

关注

评论

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

推荐一款较好的小程序管理平台

FinFish

小程序 小程序管理平台 小程序管理

Datawhale学习笔记【阿里云天池 金融风控-贷款违约预测】task1 赛题理解

一颗小树

机器学习 机器学习笔记

TiCDC 源码阅读(三)TiCDC 集群工作过程解析

PingCAP

TiDB 源码解读

2022年度回顾|龙蜥这一年:协同开放 众行致远

OpenAnolis小助手

开源社区 龙蜥 贡献 协同开放

ZBC即将登录Coinbase Institutional,2023年以全新姿态出发

BlockChain先知

ZBC即将登录Coinbase Institutional,生态开年迎新利好

鳄鱼视界

【春季2月CSM认证周末班】提前报名特惠--“全球金牌”课程CST导师亲授

ShineScrum捷行

ScrumMaster 项目经理 ScrumMaster认证 CSM认证

【春季2月A-CSM特惠周末班】ScrumMaster进阶课程 · CST导师亲授

ShineScrum捷行

敏捷教练 高阶SM 敏捷教练技能

「Go框架」剖析iris中错误码路由的运行机制

Go学堂

golang 开源 个人成长 签约计划第三季

一种面向业务配置基于JSF广播定时生效的工具

京东科技开发者

jdk 后段技术 企业号 1 月 PK 榜 ducc jsf

“零”代码改动,静态编译让太乙Stable Diffusion推理速度翻倍

OneFlow

人工智能 深度学习

【新春特惠周末班】2月4-5日在线CSPO“价值交付课程” | 全国招生

ShineScrum捷行

产品负责人 CSPO认证 CSPO

如何通过Java代码在PDF中插入、替换或删除图像?

在下毛毛雨

Java PDF 图像

采购LED显示屏要注意的五大技术参数

Dylan

LED显示屏 全彩LED显示屏 led显示屏厂家

ZBC即将登录Coinbase Institutional,生态开年迎新利好

股市老人

简述JavaScript键盘事件

devpoint

JavaScript 事件监听 事件冒泡 键盘事件

2022 年行摄回忆录

穿过生命散发芬芳

盘点2022 行摄回忆录

软件测试/测试开发 | 接口自动化测试之JSON Schema模式该如何使用?

测试人

软件测试 接口测试 测试开发 JSON Schema 测试开发自动化测试

2022年度 FinClip 扩展SDK推荐!

FinClip

从做技术到做技术管理

石云升

极客时间 技术管理 1月月更 技术领导力实战笔记

华为云服务治理 — 隔离仓的作用

秃头也爱科技

大型软件通过“云应用”即点即用,能解决元宇宙的开发之难吗?

B Impact

DCS分布式缓存服务实例类型介绍

秃头也爱科技

ZBC即将登录Coinbase Institutional,生态开年迎新利好

EOSdreamer111

“会说话”的产品包装?“码”上查看!

旺链科技

区块链 区块链技术 区块链溯源

代码影响范围工具探索

京东科技开发者

测试 源代码 企业号 1 月 PK 榜 代码影响范围

也谈证券行业数字化转型中的业务与IT融合(上)

三少爷的见

敏捷 需求管理 需求 数字化转型 需求分析

一份价格,双份收货,彻底搞定 PPT,兔年解放你自己

博文视点Broadview

揭开华为云CodeArts TestPlan启发式测试设计神秘面纱!

科技怪授

华为云

华为云发布CodeArts Req需求管理工具,让需求管理化繁为简

科技怪授

华为云

标准发布 |《企业数字化成熟度模型IOMM》(中小企业)发布

信通院IOMM数字化转型团队

数字化转型 IOMM ICT深度观察

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