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 4和case 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 尝试次数来阻止坏人压倒您的系统,限制 <T extends Short>
可能是限制将在任何一种方法调用中创建的对象。
„...这些现有的各种程序是什么样的?它们是java代码吗?…“
在 github 上搜索 T extends Integer
出现 eighty-thousand some hits。
„...与捕获的互操作性是什么意思?...“
我将捕获转换的最终解释推迟到the JLS itself。
„...为什么它很重要?...“
捕获转换很重要,因为它与类型推断有关。
the JLS' section on type inference 中的符号 ‹Integer <: α›
或多或少是表达 Integer extends Integer
的正式方式(T extends Integer
的实际含义 em>)…
…
从
Arrays.asList(1, 2.0)
,我们有约束公式‹1 → α›
和‹2.0 → > α›
。通过归约,这些将成为约束公式‹int → α›
和‹double → α›
,然后是‹Integer <: α›
和‹Double <: α›
。…
鉴于此,JDK 本身的 JDK uses <T extends Integer>
a lot for Generics/Type Inference related tests 也就不足为奇了。
这里是my absolute favorite use of <T extends Integer>
in the wild。
不过,我敢打赌,规范中与拆箱/扩展相关的更改与 Valhalla 有很大关系。
【讨论】:
感谢您的回答!请给我一些时间来理解它。 „......请给我一些时间来理解它......“ - @FrankMi - 非常欢迎你。什么,特别是,你觉得不容易理解?我非常乐意解释任何更直接/不那么冗长的东西。 TIA。以上是关于Java SE 11 - Java 语言规范中类型转换的新案例的主要内容,如果未能解决你的问题,请参考以下文章