写点什么

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

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

关注

评论

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

XSKY新一代分布式文件系统XGFS揭秘——元数据服务

XSKY星辰天合

Gitlab CI之单元测试和代码扫描

雪雷

单元测试 CI/CD gitlab ci 代码扫描

Istio微服务治理笔记(一)

雪雷

istio 服务治理 server mesh

必看的数据库使用规范

Simon

MySQL 技术规范

构建统一监管制度 加快数据要素立法修法

CECBC

区块链 金融 区块链数字经济

Java 生成解析二维码

喜瑞斯

极客公园张鹏对话百度CTO王海峰,揭秘中国AI的今昔与前路

脑极体

区块链加未来3至5年可以预见 上链将成为常态

CECBC

区块链 金融 数字时代

如何优雅的备份账号相关信息

Simon

MySQL

大数据技术思想入门(一):分布式存储特点

cristal

Java 大数据 hadoop 分布式

曾经每个手机上都有的游戏,作为前端如今你也能开发出来了,附教程

web前端程序猿

html5 大前端

支付宝蜻蜓刷脸支付

诸葛小猿

支付宝 蜻蜓 刷脸支付

Prometheus + Grafana详解

雪雷

监控 Grafana Prometheus 告警

玩K8S不得不会的HELM

雪雷

k8s Helm

一文带你检查Kubernetes应用是否为最佳实践

雪雷

k8s k8s最佳实践

赋能云端管理 激发智能边缘 英特尔发布超能云终端解决方案

最新动态

Gitlab CI进阶之共享CI库

雪雷

DevOps gitlab CI/CD gitlab ci

K8s可视化监控之-Weave Scope

雪雷

k8s k8s可视化 k8s监控

微服务链路追踪之Jaeger

雪雷

全链路监控 Jaeger

MySQL5.7应当注意的参数

Simon

MySQL 参数

Kubernetes config多集群管理工具

雪雷

k8s kubecm k8s多集群管理 kubeconfig

K8s事件监控之kube-eventer

雪雷

k8s事件告警 k8s资源监控 k8s管理

GitOps工具Argo CD实战

雪雷

DevOps CI/CD gitops argo cd

Kubernetes-学习必备(awesome-kubernetes-notes)

雪雷

学习 k8s入门 k8s文档 k8s知识

一.操作系统概述

Winter

操作系统

mPaas-RPC拦截器各种场景下的使用指南

阿里云金融线TAM SRE专家服务团队

RPC

搜狗联合清华天工研究院推出ChoreoNet模型:让数字人随着音乐翩翩起舞

脑极体

等级三整理之深信服

Lane

Git 常用命令总结

迷羊

git

小小的代码分支模型如何撬动研发过程管理

陈晨

Go: 使用pprof收集样本数据

陈思敏捷

pprof Go 语言

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