Java – 为什么char会被隐式地转换为byte(和short)原语,而不应该?

编译器的某些function让我感到困惑(使用Eclipse的Oracle JDK 1.7)。

所以我有这本书说char原语需要明确地转换为short和byte,这一切都有意义,因为数据类型的允许范围不重叠。

换句话说,下面的代码可以工作(但如果没有显式类型转换,则无法工作):

char c = '&'; byte b = (byte)c; short s = (short)c; 

正确打印b或s会显示数字38,这是Unicode中(&)的数字等效值。

这让我想到了我的实际问题。 为什么以下工作也一样?

 byte bc = '&'; short sc = '&'; System.out.println(bc); // Correctly displays number 38 on the console System.out.println(sc); // Correctly displays number 38 on the console 

现在我肯定会理解以下内容(也适用):

 byte bt = (byte)'&'; System.out.println(bt); // Correctly displays number 38 on the console 

但是对于字节(和简称)“偷偷转换”而言,这个无编译器警告字符对我来说似乎并不合适。

有人可以解释一下,为什么允许这样做?

原因可能是''本身的解释,因此它实际上并没有达到char原始状态,而是作为数字(八进制或hex等)值处理?

基本上, 赋值转换的规范指定了

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

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

你的'&'恰好是“byte,short,char或int类型的常量表达式”

这称为常量的编译时缩小 。 它在Java语言规范的5.2节中描述:

常量的编译时缩小意味着代码如下:

 byte theAnswer = 42; 

被允许。 如果没有缩小,整数文字42具有int类型的事实将意味着需要转换为字节。

字符文字也是如此:如果它的值适合一个byte ,则不需要转换; 如果值不合适,则必须进行强制转换,否则会出现编译错误。

例如,这不会编译:

 byte bc = '\uff12'; // Does not compile without a cast 

但这编译很好:

 byte bc = (byte)'\uff12'; 

我不知道这种解释是否足够,但这种行为是在JLS中定义的。 从JLS,第5.2节 :

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

  • 如果变量的类型是byte,short或char,则可以使用缩小的基元转换,并且常量表达式的值可以在变量的类型中表示。
  • 如果变量的类型是:则可以使用缩小的基元转换,然后进行装箱转换:
    • 字节和常量表达式的值可在类型字节中表示。
    • Short和常量表达式的值可以在short类型中表示。
    • 字符和常量表达式的值可在char类型中表示。

为什么以下工作也一样?

因为'&'是一个常量表达式,其值适合byte

JLS 14.4.2

如果声明符具有初始化表达式,则计算表达式并将其值分配给变量。

JLS 5.2

当表达式的值被赋值(第15.26节)给变量时,就会发生赋值转换:必须将表达式的类型转换为变量的类型。

….

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

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

变量bc的初始值设定项中的表达式’&’是一个常量表达式。 变量b和s的初始值设定项中的表达式c不是常量表达式。 当值只是常量表达式的结果时, Java在上下文需要执行基元的隐式缩小转换。