Java 13 SE规范是否不需要缓存装箱的Byte对象?

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

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

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

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

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

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

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

Byte b1=4;

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

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

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

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

guzizai2009 回答:Java 13 SE规范是否不需要缓存装箱的Byte对象?

您正确理解。该5.1.7节的最后(来自https://docs.oracle.com/javase/specs/jls/se13/html/jls-5.html)说:

如果需要分配包装类之一(布尔,字节,字符,短,整数,长,浮点或双精度)的新实例,则装箱转换可能会导致OutOfMemoryError。并且没有足够的存储空间。

如果要预先生成

Byte,就不会出现。

另一件事,仍然来自同一段:

理想情况下,将原始值装箱将始终产生相同的引用。实际上,使用现有的实现技术可能不可行。上面的规则是一种务实的折衷,要求始终将某些通用值装在无法区分的对象中。该实现可以懒惰地或急切地缓存它们。 对于其他值,该规则不允许对程序员方面的带框值的身份进行任何假设。这样可以(但不需要)共享其中一些或全部参考。


不是“证明”,但也许值得一提:Integer描述了拳击承诺,13甚至是7

 * Cache to support the object identity semantics of autoboxing for values between
 * -128 and 127 (inclusive) as required by JLS.

即使实现随时间而变化,文本也一样。

Byte没有这样的语句,尽管它也被缓存了。 713。两者都有缓存,但是没有一个单词(也没有关于装箱的单词)。

,

TL; DR已通过JDK 14(现已包括byte)修复。

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

注意JLS 6 counterpart的文本:

如果要装箱的值 p truefalse,一个byte,一个char,范围为\ u0000到\ u007f ,或介于-128和127之间的intshort数字,然后让 r1 r2 为 p。通常是 r1 == r2

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

但是请注意,没有提到long

然后,遇到JDK-7190924,5.1.7: JLS does not mention caching of autoboxed longs

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

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

他的初稿使用术语“整数文字”并完全删除了这些类型。对其进行了稍加修改的版本使其成为Java 8 JLS

如果要装箱的值pint-128之间(包括第3.10.1节)的类型127的整数文字,或者布尔文字{{ 1}}或true(§3.10.3),或介于false'\u0000'之间的字符文字(§3.10.4),然后让'\u007f'和{{ 1}}是a的任何两次拳击转换的结果。 b总是这样。

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

所以这暗示着

p

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

a == b

可能不是,因为Byte b1 = 4; 是一个常量表达式,而不是文字。

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

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

Byte b1 = (byte)4; 的遗漏肯定不是故意的,因为没有合理的理由忽略它,尤其是在以前的时候,所以从字面上看这将是一个重大突破。

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

作为旁注,Byte.valueOf(byte)的文档明确指出:

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

只要since Java 7

本文链接:https://www.f2er.com/2833317.html

大家都在问