Java SE 11 - Java 语言规范中类型转换的新案例

Posted

技术标签:

【中文标题】Java SE 11 - Java 语言规范中类型转换的新案例【英文标题】:Java SE 11 - New Cases of Type Conversion in Java Language Specification 【发布时间】:2020-12-19 02:30:50 【问题描述】:

Java SE 11 的JLS §5.2 包含了一些Java 8 的JLS 所没有的新类型转换案例,见列表中的第4 项和第5 项:

分配上下文允许使用以下之一:

    身份转换 一个扩大的基元转换 扩大参考转换 扩大参考转换,然后进行拆箱转换 扩展引用转换,然后是拆箱转换,然后是扩展基元转换 拳击转换 装箱转换,然后是扩大的参考转换 拆箱转换 拆箱转换,然后是扩大的基元转换

我不明白列表中的case 4case 5。谁能用例子给我一些解释?如果可能的话,还请解释一下它的实际用法。


更新:

作为@Naman commented,这里是更改 JLS 的建议 - JDK-8166326 : 5.2: Allow widening before unboxing,它自 Java-9 起生效。报告中提到:

此行为对于与捕获的互操作性尤为重要各种现有程序希望能够将 List<? extends Integer> 的元素视为整数。

List<? extends Integer> li = null;
int i = li.get(0);

这可能暗示这个 JLS 的改变确实有实际的必要性。但是我还是不明白为什么 extends Integer> 很重要。 与捕获的互操作性是什么意思?为什么它很重要?这些现有的各种程序是什么样的?它们是 Java 代码吗(我知道其他一些语言也可以在 JVM 上运行,并且可能与 Java 代码有交互)?

【问题讨论】:

鉴于有资格进行拆箱转换的所有 8 个类都是 final,我也看不出这两种情况的意义所在。然而,这些短语在§ 5.3、§ 5.5 和部分§ 5.6 中重复出现。 @GiorgiTsiklauri 例如,如果有人可以public class MyBoolean extends Boolean ... ,那么boolean bool = myBoolean; 工作是合乎逻辑的。但是由于我们不能从包装器扩展,我不明白我们如何才能进入需要首先扩大引用(从包装器的子类型)然后拆箱的情况。 @GiorgiTsiklauri 我想到的唯一可能性是使用 PowerMock 之类的工具来模拟(其中一个)包装器...... 这里是更改 JLS 的建议 - JDK-8166326 : 5.2: Allow widening before unboxing,自 Java-9 起生效。 @Hulk 鉴于编译器确实已经这样做了,因此无需为此寻找实际用例。确保规范和实际的编译器行为一致,已经足以推动这种改变。 【参考方案1】:

TL;DR

...拳击的问题在于它是 [ad-hoc] 且昂贵的。为了解决这两个问题,我们在后台进行了大量工作“-Brian Goetz, State of Valhalla, March 2020

这让我怀疑你提到的那些对规范的更改正在为计划中的“代码就像一个类,像一个int”功能准备语言L-World 在上面的链接中讨论过。


...谁能用例子给我一些解释?...

链接到 cmets (plus the 2013 one that one links to) 的 2016 年错误报告中的示例给出了列表中 #4 的最佳示例。基于这些,这是您列表中的 #5 示例……

< I extends Integer > void soAns0( I intRef ) 

   int intPrim;

   long longPrim = /* (3) a widening primitive conversion */
   intPrim =       /* (2) an unboxing conversion */
   intRef;         /* (1) a widening reference */

…如果可能的话,还请解释一下它的实际用法…

natural numbers 通常被称为“整数”。 Java Language Tutorial 展示了一种将自然数限制为仅属于 Integer...

类型的实际用法
public class NaturalNumber<T extends Integer> 

    private T n;

    public NaturalNumber(T n)   this.n = n; 

    public boolean isEven() 
        return n.intValue() % 2 == 0;
    

    // …

RowFilter<M,​I> 的 API 文档中也有这个示例……

…
  public boolean include(Entry<? extends PersonModel, ? extends Integer> entry) 
    …
    Person person = personModel.getPerson(entry.getIdentifier());
    …
  
…

T extends Integer 可能适用的另一个用例是,如果您想明确禁止您的类使用任何其他类型的 Number 参数化AND 明确禁止 添加 Integers 到该参数化类型中 - 通过利用Get/Put Principle.

假设您有一些代码,给定一些数字,将创建该数量的对象。 如果您想通过 Long.MAX_VALUE 的 DOS 尝试次数来阻止坏人压倒您的系统,限制 &lt;T extends Short&gt; 可能是限制将在任何一种方法调用中创建的对象。

...这些现有的各种程序是什么样的?它们是java代码吗?…

在 github 上搜索 T extends Integer 出现 eighty-thousand some hits

...与捕获的互操作性是什么意思?...

我将捕获转换的最终解释推迟到the JLS itself

...为什么它很重要?...

捕获转换很重要,因为它与类型推断有关。

the JLS' section on type inference 中的符号 ‹Integer &lt;: α› 或多或少是表达 Integer extends Integer 的正式方式(T extends Integer 的实际含义 em>)…

Arrays.asList(1, 2.0),我们有约束公式‹1 → α›‹2.0 → &gt; α›。通过归约,这些将成为约束公式‹int → α›‹double → α›,然后是‹Integer &lt;: α›‹Double &lt;: α›

鉴于此,JDK 本身的 JDK uses &lt;T extends Integer&gt; a lot for Generics/Type Inference related tests 也就不足为奇了。

这里是my absolute favorite use of &lt;T extends Integer&gt; in the wild

不过,我敢打赌,规范中与拆箱/扩展相关的更改与 Valhalla 有很大关系。

【讨论】:

感谢您的回答!请给我一些时间来理解它。 ......请给我一些时间来理解它......“ -​​ @FrankMi - 非常欢迎你。什么,特别是,你觉得不容易理解?我非常乐意解释任何更直接/不那么冗长的东西。 TIA。

以上是关于Java SE 11 - Java 语言规范中类型转换的新案例的主要内容,如果未能解决你的问题,请参考以下文章

Java SE —— 专栏总集篇

java虚拟机规范(se8)——class文件格式

Java SE基础语法知识点 (C语言快速转Java)

11.Go语言基础之接口

Java SE- 基础语法

Java SE——java语言编程练习格式化字符和常量