lpe*_*tru 6 java boxing specifications java-13
阅读 JAVA 13 SE 规范,我在第 5 章第 5.1.7 节中找到。拳击转换以下保证:
如果被装箱的值 p 是对 boolean、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);
Run Code Online (Sandbox Code Playgroud)
我们有一个byte类型的常量表达式,装箱后b1和b2的值可能是也可能不是同一个对象。
在没有演员的情况下,它实际上以相同的方式工作:
Byte b1=4;
Run Code Online (Sandbox Code Playgroud)
在这里,我们在赋值上下文中有一个 int 类型的常量表达式。所以,根据规范
如果变量的类型为 Byte、Short 或 Character,并且常量表达式的值可分别以 byte、short 或 char 类型表示,则可以使用缩窄原语转换后跟装箱转换。
因此表达式将被转换为字节,并且该字节类型的值将被装箱,因此不能保证该值是实习的。
我的问题是我对规范的解释是否正确,还是我遗漏了什么?我查看了规范是否需要使用 Byte.valueOf() 方法进行装箱(为此可以保证),但事实并非如此。
你理解正确。同一 5.1.7 部分的结尾(来自https://docs.oracle.com/javase/specs/jls/se13/html/jls-5.html)说:
如果需要分配包装类(Boolean、Byte、Character、Short、Integer、Long、Float 或 Double)之一的新实例并且没有足够的存储空间,则装箱转换可能会导致 OutOfMemoryError 。
Byte 如果预计它是预先生成的,则不会在那里。
另一件事,仍然来自同一段:
理想情况下,装箱一个原始值总是会产生一个相同的引用。实际上,使用现有的实现技术这可能是不可行的。上面的规则是一种务实的妥协,要求某些共同的价值观总是被装进无法区分的对象中。实现可能会延迟或急切地缓存这些。对于其他值,规则不允许程序员对装箱值的身份进行任何假设。这允许(但不要求)共享部分或全部这些引用。
Integer描述拳击诺言,13甚至7
Run Code Online (Sandbox Code Playgroud)* Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS.
文本是相同的,即使实现随着时间的推移而改变。
Byte没有这样的语句,尽管它也被缓存了。7,13。缓存在两者中都存在,但没有一个字关于它(也没有关于拳击)。
TL;DR 这已在JDK 14 中修复,现在包括byte.
我认为这是一个规范错误,是多次重写的结果。
请注意JLS 6 对应的文本:
如果值p被装箱是
true,false,一byte,一个char在范围\ u0000的至\ u007f,或int或short数-128和127之间,然后让R1和R2是任意两个装箱转换的结果页。r1 == r2总是如此。
在这里,byte明确提到被无条件地装箱到具有规范身份的对象。由于所有字节都在 -127..128 范围内,因此无需添加此类限制。
但请注意,long尚未提及。
然后,见JDK-7190924,5.1.7:JLS 没有提到自动装箱 longs 的缓存
在评论中,您可以看到它是如何发生的。
在他的第一条评论中,亚历克斯巴克利批评“字节是一种类型,而不是值”,没有考虑到“字节”可能意味着“字节范围内的所有值”,但由于他还假设“数字”最初意味着“文字” "(而不是例如“数值”),他关注所有整数文字要么是 int 要么是 long 的观点。
他的第一稿使用术语“整数文字”并完全删除了类型。它的一个稍微修改的版本使其成为Java 8 JLS:
如果
p被装箱的值是int介于-128和127包含(第 3.10.1 节)之间的整数文字,或布尔文字true或false(第 3.10.3 节),或介于'\u0000'和'\u007f'包含(第 3.10.4 节)之间的字符文字,则让a和b是 的任意两个装箱转换的结果p。情况总是如此a == b。
所以在 Java 8 中,类型根本不重要,但保证仅限于文字。
所以这意味着
Byte b1 = 4;
Run Code Online (Sandbox Code Playgroud)
由于整数文字,确实评估为规范对象,其中
Byte b1 = (byte)4;
Run Code Online (Sandbox Code Playgroud)
可能不是,因为它(byte)4是一个常量表达式,但不是一个文字。
多年后,在他的下一条评论中,他考虑了确实可以键入的“常量表达式”,并重新表述了该短语,将类型“boolean、char、short、int 或 long”带回来,添加了 long,但忘记了关于“字节”。
这个结果短语就是您引用的内容,自 Java 9 起就在规范中。
省略byte肯定不是故意的,因为没有合理的理由省略它,特别是当它之前存在时,所以从字面上看,这将是一个重大变化。
但是,将缓存限制为编译时常量,当 JLS 6 为范围内的所有值指定它时没有这样的限制,这已经是一个突破性的变化(这在实践中无关紧要,只要它是通过 实现的valueOf,它无法知道该值是否源自编译时常量)。
作为旁注,文档Byte.valueOf(byte)明确指出:
...所有字节值都被缓存
只要从 Java 7 开始。
| 归档时间: |
|
| 查看次数: |
185 次 |
| 最近记录: |