HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

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

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

关注

评论

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

从洞察到决策,一文解读标签画像体系建设方法论丨DTVision分析洞察篇

袋鼠云数栈

一文读懂BizDevOps:数字化转型下的技术破局

阿里云云效

技术 DevOps 云原生 数字化转型 开发.

【接入指南 之 云云接入】快速接入HONOR Connect平台(下)

荣耀开发者服务平台

开发者 IoT 新手指南 荣耀 honor

如何通过FinOps实现企业云成本优化?——信通院《中国FinOps产业发展现状研究报告》解读

星汉未来

云原生 k8s IT FinOps 云成本优化

培训预告 | 企业应用现代化实用教程——微服务治理与开发篇

York

容器 微服务 云原生 数字化转型 应用现代化

有一说一!阿里巴巴8月最新发布的这份Spring Cloud Alibaba学习笔记,几乎涵盖了其所有操作

程序员小毕

Java 程序员 面试 微服务 SpringCloud

MQTT over QUIC:下一代物联网标准协议为消息传输场景注入新动力

EMQ映云科技

车联网 物联网 mqtt emqx 8月月更

实证与虚无,抽象和具象,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang接口(interface)的使用EP08

刘悦的技术博客

Go 编程 教程 Go web 教程分享

想要精准营销,从学习搭建一套对的标签体系开始丨DTVision分析洞察篇

袋鼠云数栈

业内首份!博睿数据入选中国信通院《中国AIOps现状调查报告(2022)》

博睿数据

博睿数据 智能运维AIOps Swift AI

30分钟成为Contributor|共建测试子系统,赋能提升项目代码质量

OpenHarmony开发者

OpenHarmony

用 manim 写一个排序算法动画

ooooooh灰灰

算法 前端 后端 动画 排序

SpringMVC(五、AOP)

开源 springmvc spring aop 8月月更

解析 RocketMQ 业务消息——“事务消息”

阿里巴巴云原生

阿里云 RocketMQ 云原生 消息队列

开源项目丨一文详解一站式大数据平台运维管家ChengYing如何部署Hadoop集群

袋鼠云数栈

全新升级!《云原生架构白皮书 2022 版》重磅发布

阿里巴巴云原生

阿里云 架构 云原生 白皮书

DevSecOps|极狐GitLab IaC 安全扫描,保障云原生安全

极狐GitLab

Docker gitlab 运维 DevSecOps IaC

开源一夏 | 实战之AngularJS 的Scope和Service的深入应用心得

恒山其若陋兮

开源 8月月更

TDesign 品牌价值观

TDesign

袋鼠云申杭:数雁EasyDigit,致力成为金融行业数据洞察平台供应商的“领头雁”

袋鼠云数栈

自动化测试-存储测试用例,哪个更好

和牛

Python 自动化 测试 8月月更

1分钟创建3000台云电脑 阿里云无影发布多款千人协同生产力方案

Lily

落地DevOps,探索高效研发运营一体化解决方案

云智慧AIOps社区

DevOps 质量管理 代码管理 自动化运维 研发效率

A tour of gRPC:07 - gRPC bidirectional straming 双向流

BUG侦探

gRPC RPC protocolBuffer

如何提升IT对业务发展的贡献度

凌晞

数字化 构架 IT管理

“阿里爸爸”最新总结的303页Spring全家桶高级笔记,都是面试必问的知识点

Java工程师

Java spring Spring全家桶

活动报名| MongoDB 使用规范及最佳实践线上直播来啦!

MongoDB中文社区

mongodb

化整为零优化重用,Go lang1.18入门精炼教程,由白丁入鸿儒,go lang函数的定义和使用EP07

刘悦的技术博客

Go 教程 Go web 教程分享

我们总结了 3 大使用建议,并首次公开 Nacos 3.0 规划图 | Nacos 开源 4 周年

阿里巴巴云原生

阿里云 开源 微服务 云原生 nacos

深度学习公式推导:从神经元出发

老崔说架构

直播预告 | 如何从 0 到 1 打造敏捷团队?

Authing

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