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* ? [复制]