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

huangapple go评论89阅读模式
英文:

Java SE 11 - New Cases of Type Conversion in Java Language Specification

问题

JLS §5.2 of Java SE 11 contains some new type conversion cases which JLS of Java 8 doesn't have, see item 4 and item 5 in the list:

>Assignment contexts allow the use of one of the following:
> 1. an identity conversion
> 2. a widening primitive conversion
> 3. a widening reference conversion
> 4. a widening reference conversion followed by an unboxing conversion
> 5. a widening reference conversion followed by an unboxing conversion, then followed by a widening primitive conversion
> 6. a boxing conversion
> 7. a boxing conversion followed by a widening reference conversion
> 8. an unboxing conversion
> 9. an unboxing conversion followed by a widening primitive conversion


Update:

As @Naman commented, here is the proposal to change the JLS - JDK-8166326 : 5.2: Allow widening before unboxing which was in effect since Java-9. In the report, it mentioned:

>This behavior is especially important for interoperability with capture: various existing programs expect to be able to treat the elements of a List<? extends Integer> as if they were ints.
>
> List<? extends Integer> li = null;
> int i = li.get(0);

英文:

JLS §5.2 of Java SE 11 contains some new type conversion cases which JLS of Java 8 doesn't have, see item 4 and item 5 in the list:

>Assignment contexts allow the use of one of the following:
> 1. an identity conversion
> 2. a widening primitive conversion
> 3. a widening reference conversion
> 4. a widening reference conversion followed by an unboxing conversion
> 5. a widening reference conversion followed by an unboxing conversion, then followed by a widening primitive conversion
> 6. a boxing conversion
> 7. a boxing conversion followed by a widening reference conversion
> 8. an unboxing conversion
> 9. an unboxing conversion followed by a widening primitive conversion

I don't understand the case 4 and case 5 in the list. Could anyone give me some explanation with examples? If possible, please also explain its practical usage.


Update:

As @Naman commented, here is the proposal to change the JLS - JDK-8166326 : 5.2: Allow widening before unboxing which was in effect since Java-9. In the report, it mentioned:

>This behavior is especially important for interoperability with capture: various existing programs expect to be able to treat the elements of a List&lt;? extends Integer&gt; as if they were ints.
>
> List<? extends Integer> li = null;
> int i = li.get(0);

This may imply that this JLS change do have a practical necessary. But I still don't understand why <? extends Integer> is important. What does interoperability with capture mean and why is it important? What do these various existing programs look like? Are they java code (I know some other languages also work on JVM and may have interaction with Java code)?

答案1

得分: 1

TL;DR

"问题在于装箱是一种特例方法且代价高昂;在底层已经进行了大量工作来解决这些问题。" — Brian Goetz,《瓦哈拉状态》,2020年3月

这让我怀疑你所提到的规范变更是为了准备语言,以适应上面链接中讨论的 L-World 中计划中的 "像类一样编码,像 int 一样工作" 的能力。


"…有人能给我一些解释和示例吗?…"

在评论中链接的2016年的错误报告中的示例(以及链接到的2013年的错误报告)最好地说明了你列表中的第 4 条。基于这些,以下是你列表中第 5 条的示例…

  1. < I extends Integer > void soAns0( I intRef ) {
  2. int intPrim;
  3. long longPrim = /* (3) 扩宽原始转换 */
  4. intPrim = /* (2) 拆箱转换 */
  5. intRef; /* (1) 扩宽引用 */
  6. }

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

"自然数" 通常被称为 "整数"。Java 语言教程展示了将自然数限制为仅为 Integer 类型的一个实际用法…

  1. public class NaturalNumber<T extends Integer> {
  2. private T n;
  3. public NaturalNumber(T n) { this.n = n; }
  4. public boolean isEven() {
  5. return n.intValue() % 2 == 0;
  6. }
  7. // ...
  8. }

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

  1. ...
  2. public boolean include(Entry<? extends PersonModel, ? extends Integer> entry) {
  3. ...
  4. Person person = personModel.getPerson(entry.getIdentifier());
  5. ...
  6. }
  7. ...

还有一个使用 T extends Integer 的用例是,如果你想明确禁止类以任何其他类型的 Number 进行参数化,并明确禁止将 Integers 添加到该参数化类型中,可以利用“获取/放置原则”。

假设你有一些代码,根据某个数字将创建这么多对象。如果你想阻止不良行为者通过向系统轰炸 Long.MAX_VALUE 次 DOS 尝试来淹没系统,使用 &lt;T extends Short&gt; 可能是限制在任何一个方法调用中会创建的对象数量的一种方法。

"…这些 各种现有程序 是什么样子?它们是 Java 代码吗?…"

在 GitHub 上搜索 T extends Integer,会得到 八万多个结果

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

我将捕获转换的详细解释推迟给 JLS 本身

"…为什么它很重要?…"

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

JLS 中关于类型推断的部分中的表示 ‹Integer &lt;: α› 在很大程度上是表达 Integer extends Integer(即 T extends Integer 的有效含义)的正式方式。

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

鉴于此,不难理解 JDK 在自身的测试中经常使用 &lt;T extends Integer&gt; 进行泛型/类型推断相关的测试。

这是我在实际代码中最喜欢的 &lt;T extends Integer&gt; 的用法

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

英文:

TL;DR

> „…The problem with boxing is that it is [ad-hoc] and expensive; extensive work has gone on under the hood to address both of these concerns“ — Brian Goetz, State of Valhalla, March 2020

That makes me suspect that those changes to the spec you refer to are preparing the language for the planned „Codes like a class, works like an int“ capabilities of L-World discussed in the above link.


> „…Could anyone give me some explanation with examples?…

The example in the 2016 bug report linked to in the comments (plus the 2013 one that one links to) gives the best example of #4 in your list. Based on those, here's an example of #5 in your list…

  1. &lt; I extends Integer &gt; void soAns0( I intRef ) {
  2. int intPrim;
  3. long longPrim = /* (3) a widening primitive conversion */
  4. intPrim = /* (2) an unboxing conversion */
  5. intRef; /* (1) a widening reference */
  6. }

> „…If possible, please also explain its practical usage…

The natural numbers are often referred to as „integers“. The Java Language Tutorial shows one practical usage of restricting the natural numbers to only be of type Integer

  1. public class NaturalNumber&lt;T extends Integer&gt; {
  2. private T n;
  3. public NaturalNumber(T n) { this.n = n; }
  4. public boolean isEven() {
  5. return n.intValue() % 2 == 0;
  6. }
  7. // …
  8. }

There's also this example in the API documentation for RowFilter<M,​I>

  1. public boolean include(Entry&lt;? extends PersonModel, ? extends Integer&gt; entry) {
  2. Person person = personModel.getPerson(entry.getIdentifier());
  3. }

Another use case where T extends Integer might be appropriate is if you want to explicitly forbid your class from being parameterized with any other type of Number AND explicitly forbid adding Integers into that parameterized type — by leveraging the Get/Put Principle.

Say you have some code that, given some number, will create that number of objects.
If you want to forbid bad actors from overwhelming your system by bombarding it with Long.MAX_VALUE number of DOS attempts, bounding &lt;T extends Short&gt; could be one way to limit the number of objects that would get created in any one method call.

> „…What do these various existing programs look like? Are they java code?…

A search on github for T extends Integer turns up eighty-thousand some hits.

> „…What does interoperability with capture mean?…

I defer the definitive explanation of capture conversion to the JLS itself.

> „…and why is it important?…

Capture conversion is important because of it's connection to type inference.

The notation ‹Integer &lt;: α› in the JLS' section on type inference is more or less a formal way of expressing Integer extends Integer (what T extends Integer effectively means)…

> …
>
> From Arrays.asList(1, 2.0), we have the constraint formulas ‹1 → α› and ‹2.0 → &gt; α›. Through reduction, these will become the constraint formulas ‹int → α› and
> ‹double → α›, and then ‹Integer &lt;: α› and ‹Double &lt;: α›.

>
> …

Given that, it's not surprising that the JDK uses &lt;T extends Integer&gt; a lot for Generics/Type Inference related tests of the JDK itself.

Here's my absolute favorite use of &lt;T extends Integer&gt; in the wild.

Mostly though, I would bet those unboxing-/widening-related changes to the spec have more than a little to do with Valhalla.

huangapple
  • 本文由 发表于 2020年8月31日 06:53:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/63662871.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定