8

编译器的某些功能让我感到困惑(使用 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>'自身的解释,因此它实际上不会进入 char 原始状态,而是作为数字(八进制或十六进制等)值处理?

4

5 回答 5

8

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

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

如果变量的类型是 byte、short 或 char,并且常量表达式的值可以用变量的类型表示,则可以使用窄化原语转换。

'&'正是“byte、short、char 或 int 类型的常量表达式”

于 2013-06-12T10:51:31.047 回答
7

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

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

byte theAnswer = 42;

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

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

例如,这不会编译:

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

但这编译得很好:

byte bc = (byte)'\uff12';
于 2013-06-12T10:52:23.720 回答
1

为什么以下也有效?

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

JLS 14.4.2

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

JLS 5.2

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

……

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

  • 如果变量的类型是 byte、short 或 char,并且常量表达式的值可以用变量的类型表示,则可以使用窄化原语转换。
于 2013-06-12T10:45:36.963 回答
1

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

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

  • 如果变量的类型是 byte、short 或 char,并且常量表达式的值可以用变量的类型表示,则可以使用窄化原语转换。
  • 如果变量的类型是:
    • 字节和常量表达式的值可以用字节类型表示。
    • Short 并且常量表达式的值可以用 short 类型表示。
    • 字符和常量表达式的值可以用 char 类型表示。
于 2013-06-12T10:51:01.593 回答
0

变量 bc 的初始化程序中的表达式 '&' 是一个常量表达式。变量 b 和 s 的初始化程序中的表达式 c 不是常量表达式。当值仅是常量表达式的结果时,当上下文需要时,Java 会执行原语的隐式缩小转换。

于 2013-06-12T10:51:23.063 回答