Java 13 SE规范是否不需要缓存装箱的Byte对象? [英] Is caching of boxed Byte objects not required by Java 13 SE spec?

查看:139
本文介绍了Java 13 SE规范是否不需要缓存装箱的Byte对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读JAVA 13 SE规范,我在第5章的5.1.7节中找到了.拳击转换具有以下保证:

Reading the JAVA 13 SE specification, I found in chapter 5, section 5.1.7. Boxing Conversion the following guarantee:

如果装箱的值p是求常数的结果 布尔值,char,short,int或long类型的表达式(第15.28节),以及 结果为true,false,范围为'\ u0000'到 '\ u007f'(含端点)或-128至127(含)范围内的整数, 然后令a和b为p的任何两次装箱转换的结果.它 总是a == b

If the value p being boxed is the result of evaluating a constant expression (§15.28) of type boolean, char, short, int, or long, and the result is true, false, a character in the range '\u0000' to '\u007f' inclusive, or an integer in the range -128 to 127 inclusive, then let a and b be the results of any two boxing conversions of p. It is always the case that a == b

我发现奇怪的是,在该措辞中遗漏了字节类型的值.

I find it odd that values of type byte are left out from that wording.

例如,在诸如以下的代码中

For example, in a code such as:

Byte b1=(byte)4;
Byte b2=(byte)4;
System.out.println(b1==b2);

我们有一个类型为byte的常量表达式,在装箱后,b1和b2的值可能是同一对象,也可能不是同一对象.

We have a constant expression of type byte, and after the boxing, the values of b1 and b2 may or may not be the same object.

实际上,无需强制转换,其工作方式相同:

It works actually the same way without the cast:

Byte b1=4;

在这里,我们在赋值上下文中有一个int类型的常量表达式.因此,根据规范

Here, we have a constant expression of type int in an assignment context. So, according to the spec

缩小的原始转换后跟拳击转换可能 如果变量的类型为Byte,Short或Character,并且使用 常量表达式的值可以在类型字节中表示, short或char.

A narrowing primitive conversion followed by a boxing conversion may be used if the variable is of type Byte, Short, or Character, and the value of the constant expression is representable in the type byte, short, or char respectively.

因此表达式将被转换为字节,并且该字节类型的值将被装箱,因此不能保证该值是可插入的.

So the expression will be converted to byte, and that byte type value will be boxed, so there is no guarantee that the value is interned.

我的问题是我在解释规范时是对的还是遗漏了某些东西?我查看了规范是否要求对装箱使用Byte.valueOf()方法(这将得到保证),但事实并非如此.

My question is am I right in interpreting the spec, or am I missing something? I have looked if the spec requires using of method Byte.valueOf() for the boxing (for which it would be guaranteed), but it does not.

推荐答案

TL; DR已使用

TL;DR this has been fixed with JDK 14, which now includes byte.

我认为这是一个规范错误,是多次重写的结果.

I consider this a specification bug, result of multiple rewritings.

请注意与JLS 6对应的文本:

如果要装箱的值 p truefalsebyte,范围在\ u0000到\ u007f之间的charintshort在-128到127之间的数字,然后让 r1 r2 p的任何两次装箱转换的结果. r1 == r2 的情况.

If the value p being boxed is true, false, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

在这里,明确地提到byte是无条件地装箱到具有规范标识的对象.由于所有字节都在-127..128范围内,因此无需添加此类限制.

Here, byte is explicitly mentioned as being boxed to an object with canonical identity, unconditionally. Since all bytes are in the -127..128 range, there was no need for adding such a restriction.

但是请注意,没有提到long.

But note that long has not been mentioned.

然后,见面 JDK-7190924,5.1.7:JLS没有提到缓存自动装箱的多头

在评论中,您可以看到它是如何发生的.

In the comments, you can see, how it happened.

亚历克斯·巴克利(Alex Buckley)在第一条评论中批评字节是一种类型,而不是一个值",没有考虑到字节"可能意味着字节范围内的所有值",但是由于他还假定数字"最初是他的意思是文字"(而不是数值"),他着眼于所有整数文字都是int或long的观点.

In his first comment, Alex Buckley criticizes that "byte is a type, not a value", not considering that "byte" could mean "all values in the byte range", but since he also assumes that "number" originally meant "literal" (instead of, e.g. "numeric value"), he focuses on the point that all integer literals are either int or long.

他的初稿使用了整数文字"一词​​,并完全删除了这些类型.经过稍微修改的版本使其成为 Java 8 JLS :

His first draft uses the term "integer literal" and removes the types completely. A slightly modified version of it made it into the Java 8 JLS:

如果要装箱的值p是介于-128127(包括第3.10.1节)之间的int类型的整数文字,或者是布尔文字truefalse(第3.10节) .3)或'\u0000''\u007f'(含)之间的字符文字(第3.10.4节),然后让abp的任何两次装箱转换的结果. a == b总是如此.

If the value p being boxed is an integer literal of type int between -128 and 127 inclusive (§3.10.1), or the boolean literal true or false (§3.10.3), or a character literal between '\u0000' and '\u007f' inclusive (§3.10.4), then let a and b be the results of any two boxing conversions of p. It is always the case that a == b.

因此在Java 8中,类型根本无关紧要,但是保证仅限于文字.

So in Java 8, the type doesn't matter at all, but the guaranty is limited to literals.

所以这暗示着

Byte b1 = 4;

由于整数字面量而求值为规范对象,其中as

does evaluate to a canonical object due to the integer literal, where as

Byte b1 = (byte)4;

可能不是,因为(byte)4是常量表达式而不是文字.

may not, as (byte)4 is a constant expression but not a literal.

几年后,在他的下一条评论中,他认为确实可以键入的常量表达式",并重新定义了该短语,并带回了"boolean,char,short,int或long"类型,并添加了long. ,但忘记了字节".

In his next comment, years later, he considers "constant expressions", which can indeed be typed, and reformulates the phrase, bringing back the types, "boolean, char, short, int, or long", having added long, but forgotten about "byte".

这个结果短语就是您引用的,这是Java 9以来的规范.

This resulting phrase is what you've cited, which is in the specification since Java 9.

byte的省略肯定不是故意的,因为没有合理的理由忽略它,尤其是在以前的时候,所以从字面上看,这将是一个重大突破.

The omission of byte surely isn't intentional, as there is no plausible reason to omit it, especially, when it was there before, so this would be a breaking change when taken literally.

但是,将缓存限制为编译时常量时,当JLS 6为范围内的所有值指定缓存而没有这种限制时,这已经是一个重大更改(实际上,只要实现就没有关系)通过valueOf,它无法知道该值是否源自编译时常量.

Though, restricting the caching to compile-time constants, when JLS 6 specified it for all values in the range without such a restriction, is already a breaking change (which doesn't matter in practice, as long as it is implemented via valueOf, which has no way of knowing whether the value originated from a compile-time constant or not).

作为旁注,

As a side note, the documentation of Byte.valueOf(byte) explicitly says:

...所有字节值都已缓存

...all byte values are cached

只要自Java 7 .

这篇关于Java 13 SE规范是否不需要缓存装箱的Byte对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆