Java - 为啥 char 不应该被隐式转换为字节(和短)原语?

Posted

技术标签:

【中文标题】Java - 为啥 char 不应该被隐式转换为字节(和短)原语?【英文标题】:Java - why does char get implicitly cast to byte (and short) primitive, when it shouldn't?Java - 为什么 char 不应该被隐式转换为字节(和短)原语? 【发布时间】:2013-06-08 10:38:51 【问题描述】:

编译器的某些功能让我感到困惑(使用 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 原始状态,而是作为数字(八进制或十六进制等)值处理?

【问题讨论】:

简单地说,编译器可以确定一个常量是否可以安全地缩小范围。如果有精度损失会产生编译时错误,试试这个比较一下:byte b = '\u20AC'; 【参考方案1】:

为什么以下方法也有效?

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

JLS 14.4.2

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

JLS 5.2

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

....

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

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

【讨论】:

【参考方案2】:

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

此外,如果表达式是 类型的常量表达式(§15.28) 字节、短、字符或整数:

缩小原语转换可能 如果变量的类型是 byte、short 或 char,以及 常量表达式是 可表示的类型 多变的。 缩小原语 转换后是拳击 转换可以使用,如果类型 变量是: 字节和值 常量表达式是 可以用类型字节表示。 短 和常数的值 表达式可以在 键入简短。 字符和值 常量表达式是 可以用 char 类型表示。

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

基本上,specification of assignment conversion 指定

另外,如果表达式是一个常量表达式(§15.28) 输入 byte、short、char 或 int:

如果类型为 变量是 byte、short 或 char,以及常量的值 表达式可以用变量的类型来表示。

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

【讨论】:

虽然引用是正确的(对分配规范),但引用的第一个段落相关。这些赋值示例中没有参数化类型。只有第二段适用。【参考方案5】:

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

常量的编译时变窄意味着代码如:

byte theAnswer = 42;

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

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

例如,这不会编译:

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

但这编译得很好:

byte bc = (byte)'\uff12';

【讨论】:

以上是关于Java - 为啥 char 不应该被隐式转换为字节(和短)原语?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这里不发生隐式转换?

为啥仅在某些情况下才能将字符串文字隐式转换为 char* ? [复制]

为啥Java没有复制构造函数?

为啥 Java 和 C# 没有到布尔值的隐式转换?

AWS System Manager GetParameters 权限被隐式拒绝

我定义了一个非拷贝构造函数;复制构造函数是不是仍会被隐式定义?