Java扩展转换

Phi*_*hew 25 java

我正在准备Java 7认证,并提出以下问题.

Byte b = 10编译确定.看起来编译器正在缩小int 10到byte 10然后装箱.怎么Byte b = new Byte(10)会不编译?为什么编译器不能像第一种情况那样缩小int 10到byte 10?

如何Long l = new Long(10)编译好但却Long l = 10失败了?

我不清楚它是如何工作的.有人可以提供明确的解释吗?

rge*_*man 20

JLS的5.2节介绍了赋值上下文中允许的转换类型.

赋值上下文允许使用以下之一:

  • 身份转换(§5.1.1)

  • 扩展的原始转换(第5.1.2节)

  • 扩大参考转换(第5.1.5节)

  • 一个拳击转换(§5.1.7),可选地后跟一个加宽的引用转换

另外,

此外,如果表达式是byte,short,char或int类型的常量表达式(第15.28节):

  • 如果变量的类型是byte,short或char,则可以使用缩小的基元转换,并且常量表达式的值可以在变量的类型中表示.

  • 如果变量的类型是:则可以使用缩小的基元转换,然后进行装箱转换:

    • 字节和常量表达式的值可在类型字节中表示.

    • Short和常量表达式的值可以在short类型中表示.

    • 字符和常量表达式的值可在char类型中表示.

Byte b = 10编译好因为10是一个常量表达式并且可以表示为byte.

Byte b = new Byte(10)将不会编译因为10int文字,并且方法调用转换不会执行原始缩小转换.要调用Byte构造函数进行编译,可以显式转换10byte:

Byte b = new Byte( (byte) 10);
Run Code Online (Sandbox Code Playgroud)

Long l = new Long(10)编译因为方法调用转换将执行原始扩展转换,包括from intlong.

Long l = 10不会编译,因为Java不会特别允许扩展转换,然后进行装箱转换,正如我在最近的回答中所讨论的那样.要使其编译,您可以使用long文字,因此只需要装箱.

Long l = 10L;
Run Code Online (Sandbox Code Playgroud)


ysh*_*vit 10

基本规则是:

  • 你不能一步转换和自动转发(JLS 5.1.7定义装箱转换,它不包括转换和自动转换类型转换,所以不允许)
  • 你不能隐含地缩小类型

这些规则解释了为什么Long l = 10不起作用,以及new Byte(10).第一个要求将int literal 10扩展为a long然后加框,这是不允许的.(更准确地说,它需要转换intLong,JLS 5.1.7没有定义.)第二个要求将int literal 10隐式缩小为a byte,这是不允许的.

但该规则有例外.JLS 5.2Byte b = 10明确允许:

此外,如果表达式类型的常量表达式(§15.28) ,byte,short,charint:

  • 如果变量的类型是:则可以使用缩小的基元转换,然后进行装箱转换:
    • Byte并且常量表达式的值可在类型中表示byte.

(省略了一些不相关的部分)

最后,new Long(10)因为int literal 10 可以自动加宽到10L.


NES*_*ove 1

10 是一个整数文字,您必须将其向下转换才能将其传递给 Byte 构造函数。不幸的是,也没有字节文字语法可以删除强制转换。

另外,为什么 Long l = new Long(10) 编译正常但 Long l = 10 失败?

因为 10 作为一个整数,可以毫无问题地放入 long 中。整数无法放入字节中,因此在这种情况下需要进行强制转换(扩大转换)。

此转换也是编译时,因为它也是扩大转换。查看 JLS 中的第 5.1.5 节

加宽引用转换在运行时不需要特殊操作,因此永远不会在运行时抛出异常。它们只是将引用视为具有某种其他类型,并且可以在编译时证明其正确性。