【AICon】AI 基础设施、LLM运维、大模型训练与推理,一场会议,全方位涵盖! >>> 了解详情
写点什么

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

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

关注

评论

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

如何在 macOS 中互换 Control 和 Command 键

魔仙苹果mac堡

mac教程 Control键 Command 键

CleanMyMac4.20专业的mac清理软件

茶色酒

CleanMyMac4.20

SpringBoot项目就连创建目录都让人抓狂

做梦都在改BUG

Java Spring Boot 框架

ElasticSearch必知必会-Reindex重建索引

京东科技开发者

elasticsearch 索引 ES 集群 企业号 3 月 PK 榜

OPPO、京东云 loT 项目数据架构改造,数据处理痛点这样破解

TDengine

tdengine 数据架构 时序数据库 用户案例 loT

真香!阿里最新出品Java面试核心讲(终极版),Github已星标50K

程序员小毕

Java 程序员 面试 后端 架构师

虎牙SRE谈可观测:如何做到比用户和老板更早发现业务异常?

TakinTalks稳定性社区

Mac教程:如何开启任何来源选项

魔仙苹果mac堡

Mac 苹果电脑 任何来源

解决 Parallels Desktop 虚拟机不能连网的问题

魔仙苹果mac堡

Parallels Desktop 虚拟机 PD虚拟机不能联网 PD常见问题

喜讯|百度入选“移动互联网APP产品安全漏洞治理”优秀案例

百度安全

设备使用HTTPS协议接入IoT物联网平台——设备接入类

阿里云AIoT

Spring源码解析-Spring AOP

Java你猿哥

Java 源码 云原生 Spring Boot ssm

业务架构那点事(2)如何通过高层访谈获取企业战略信息?

涛哥 数字产品和业务架构

业务架构 访谈

面面俱到!四面阿里拿offer后,才发现师哥给的面试笔记有多强大

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

支付宝小程序-MQTT模拟器体验阿里云IoT开发——设备接入类

阿里云AIoT

物联网

企业不想走弯路,不如试试低代码开发

引迈信息

低代码 低代码开发 JNPF

订阅标识符与订阅选项--MQTT 5.0新特性

EMQ映云科技

物联网 IoT mqtt 订阅 企业号 3 月 PK 榜

跨平台开发成为移动应用程序开发趋势

没有用户名丶

中国流程挖掘迎来新“启点”,望繁信科技全面升级

ToB行业头条

国产操作系统应用开发的趋势与挑战

没有用户名丶

业务系统故障率居高不下:有哪些非常有效的治理大招?

TakinTalks稳定性社区

直播教学!20 分钟开发可视化「智能门铃」丨RTE 开发实战课 • 第一期

声网

最佳实践 直播 RTC 声网

金三突击面试,收获6个Offer,原来面试还能这么简单!

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

Last Week in Milvus

Zilliz

Milvus Zilliz 向量数据库

亿级用户中心的设计与实践

做梦都在改BUG

Java 服务架构 亿级流量 用户中心

通过Flutter实现一个能在多端运行的扫雷游戏

编程的平行世界

flutter 前端 游戏 移动端 扫雷

K8S部署应用详解

tiandizhiguai

使用抓包工具Wireshark分析IoT设备网络行为——设备管理运维类

阿里云AIoT

网络协议 物联网 网络性能优化

国家中心城市手机银行发展洞察

易观分析

金融 经济 手机银行 城市

「危险」的ChatGPT,聊天机器人式越狱,带来的法律挑战

这我可不懂

低代码平台 ChatGPT JNPF

你值得拥有的IoT 物联网平台开发实用技巧(一)——数据价值类

阿里云AIoT

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