简体   繁体   English

Java 13 SE 规范不需要缓存盒装 Byte 对象吗?

[英]Is caching of boxed Byte objects not required by Java 13 SE spec?

Reading the JAVA 13 SE specification, I found in chapter 5, section 5.1.7.阅读 JAVA 13 SE 规范,我在第 5 章第 5.1.7 节中找到。 Boxing Conversion the following guarantee:拳击转换以下保证:

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 '\' to '\' 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.如果被装箱的值 p 是对 boolean、char、short、int 或 long 类型的常量表达式(第 15.28 节)求值的结果,并且结果为 true、false,则为 '\' 到 ' 范围内的字符\'(含),或 -128 到 127(含)范围内的整数,然后让 a 和 b 是 p 的任意两次装箱转换的结果。 It is always the case that a == b 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);

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.我们有一个byte类型的常量表达式,装箱后b1和b2的值可能是也可能不是同一个对象。

It works actually the same way without the cast:在没有演员的情况下,它实际上以相同的方式工作:

Byte b1=4;

Here, we have a constant expression of type int in an assignment context.在这里,我们在赋值上下文中有一个 int 类型的常量表达式。 So, according to the spec所以,根据规范

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.如果变量的类型为 Byte、Short 或 Character,并且常量表达式的值可分别以 byte、short 或 char 类型表示,则可以使用缩窄原语转换后跟装箱转换。

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.因此表达式将被转换为字节,并且该字节类型的值将被装箱,因此不能保证该值是实习的。

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.我查看了规范是否需要使用方法 Byte.valueOf() 进行装箱(为此可以保证),但事实并非如此。

You understand it correctly.你理解正确。 The end of the same 5.1.7 section (from https://docs.oracle.com/javase/specs/jls/se13/html/jls-5.html ) says:同一 5.1.7 部分的结尾(来自https://docs.oracle.com/javase/specs/jls/se13/html/jls-5.html )说:

A boxing conversion may result in an OutOfMemoryError if a new instance of one of the wrapper classes (Boolean, Byte , Character, Short, Integer, Long, Float, or Double) needs to be allocated and insufficient storage is available.如果需要分配包装类(Boolean、 Byte 、Character、Short、Integer、Long、Float 或 Double)之一的新实例并且没有足够的存储空间,则装箱转换可能会导致 OutOfMemoryError。

Byte would not be there if it was expected to be pre-generated.如果希望预先生成Byte ,则它不会存在。

Another thing, still from the same paragraph:另一件事,仍然来自同一段:

Ideally, boxing a primitive value would always yield an identical reference.理想情况下,装箱一个原始值总是会产生一个相同的引用。 In practice, this may not be feasible using existing implementation techniques.实际上,使用现有的实现技术这可能是不可行的。 The rule above is a pragmatic compromise, requiring that certain common values always be boxed into indistinguishable objects.上面的规则是一种务实的妥协,要求某些共同的价值观总是被装进无法区分的对象中。 The implementation may cache these, lazily or eagerly.实现可能会延迟或急切地缓存这些。 For other values, the rule disallows any assumptions about the identity of the boxed values on the programmer's part .对于其他值,规则不允许程序员对装箱值的身份进行任何假设 This allows ( but does not require ) sharing of some or all of these references.这允许(但不要求)共享部分或全部这些引用。


Not a "proof", but perhaps it is worth to mention: Integer describes the boxing promise, 13 and even 7 不是“证明”,但也许值得一提: Integer描述了拳击承诺, 13甚至7

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

The text is the same, even though the implementation has changed over time.文本是相同的,即使实现随着时间的推移而改变。

Byte has no such statement, though it is cached too. Byte没有这样的语句,尽管它也被缓存了。 7 , 13 . 713 The cache is there in both, but there is not a single word about it (and neither about boxing).缓存在两者中都存在,但没有一个字关于它(也没有关于拳击)。

TL;DR this has been fixed with JDK 14 , which now includes byte . TL;DR 这已在JDK 14 中修复,现在包含byte

I consider this a specification bug, result of multiple rewritings.我认为这是一个规范错误,是多次重写的结果。

Note the text of the JLS 6 counterpart :注意JLS 6 对应的文本:

If the value p being boxed is true , false , a byte , a char in the range \ to \, 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.如果被装箱的值ptruefalse 、一个byte 、一个 \ 到 \ 范围内的char ,或者一个介于 -128 和 127 之间的intshort数,那么让r1r2是任何两个装箱转换的结果p. 的It is always the case that r1 == r2 . r1 == r2总是如此。

Here, byte is explicitly mentioned as being boxed to an object with canonical identity, unconditionally.在这里,明确提到byte被无条件地装箱到具有规范身份的对象。 Since all bytes are in the -127..128 range, there was no need for adding such a restriction.由于所有字节都在 -127..128 范围内,因此无需添加此类限制。

But note that long has not been mentioned.但请注意,没有提到long

Then, meet JDK-7190924, 5.1.7: JLS does not mention caching of autoboxed longs然后,见JDK-7190924,5.1.7:JLS 没有提到自动装箱 longs 的缓存

In the comments, you can see, how it happened.在评论中,您可以看到它是如何发生的。

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, eg "numeric value"), he focuses on the point that all integer literals are either int or long.在他的第一条评论中,亚历克斯巴克利批评“字节是一种类型,而不是值”,没有考虑到“字节”可能意味着“字节范围内的所有值”,但由于他还假设“数字”最初意味着“文字” "(而不是例如“数值”),他关注所有整数文字要么是 int 要么是 long 的观点。

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 :它的一个稍微修改的版本使其成为Java 8 JLS

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 '\' and '\' inclusive (§3.10.4), then let a and b be the results of any two boxing conversions of p .如果被装箱的值p是介于-128127之间的int类型整数文字(第 3.10.1 节),或布尔文字truefalse (第 3.10.3 节),或介于'\''\'包含(第 3.10.4 节),然后让abp的任何两个装箱转换的结果。 It is always the case that a == b .总是a == b的情况。

So in Java 8, the type doesn't matter at all, but the guaranty is limited to literals.所以在 Java 8 中,类型根本不重要,但保证仅限于文字。

So this would imply that所以这意味着

Byte b1 = 4;

does evaluate to a canonical object due to the integer literal, where as由于整数文字,确实评估为规范对象,其中

Byte b1 = (byte)4;

may not, as (byte)4 is a constant expression but not a literal.可能不是,因为(byte)4是一个常量表达式而不是一个文字。

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".多年后,在他的下一条评论中,他考虑了确实可以键入的“常量表达式”,并重新表述了该短语,将类型带回了“boolean、char、short、int 或 long”,添加了 long,但忘记了关于“字节”。

This resulting phrase is what you've cited, which is in the specification since Java 9.这个结果短语就是您引用的内容,自 Java 9 起就在规范中。

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.省略byte肯定不是故意的,因为没有合理的理由省略它,特别是当它之前存在时,所以从字面上看,这将是一个重大变化。

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).虽然,将缓存限制为编译时常量,当 JLS 6 为范围内的所有值指定它时没有这样的限制,这已经是一个突破性的变化(这在实践中无关紧要,只要它是通过valueOf实现的,无法知道该值是否源自编译时常量)。

As a side note, the documentation of Byte.valueOf(byte) explicitly says:作为旁注, Byte.valueOf(byte)的文档明确指出:

...all byte values are cached ...所有字节值都被缓存

as long as since Java 7 .只要从 Java 7 开始

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM