Java字符类型转换为字节类型

23

我一直在测试字符转换,我经历了以下情况:

public class Test {
    public static void main(String a[]) {
        final byte b1 = 1;
        byte b2 = 1;
        char c = 2;

        c = b1; // 1- Working fine
        c = b2; // 2 -Compilation error
    }
}

请问为什么我在 byte 变量后面加了 final 关键字后,在第一个版本中代码可以正常运行?


通常情况下,从字节到字符的转换以及反之并不是一个好的实践,因为这会忽略编码。 - Necreaux
3个回答

19

当变量为final时,编译器会自动将其值内联,该值为1。该值可表示为char,即:

当变量使用final关键字进行修饰时,编译器会在编译期间自动将该变量的值直接嵌入到代码中,取代原本的变量引用。对于值为1的情况,它可以被表示为一个char类型的数据。

c = b1;

等同于

c = 1;

实际上,根据关于final变量的这一部分内容b1被视为常量:

一个原始类型或类型为 String、并且被初始化为编译时常量表达式 (§15.28) 的 final 变量称为常量变量。


2
仍然不应有任何差别。 - loonytune
3
是的,编译器会这样做。使用 javac 1.7.0_75 进行验证。 - M A
1
你说得对,Java 8 上也经过验证。我真的很惊讶,这可能与它在编译期间作为符号表中的常量条目有关,根本不是变量。对此感到抱歉,已经点赞了你的评论和答案... - loonytune
@loonytune 没问题。在这种情况下,b1实际上是一个常量变量(你的推理是正确的)。这就是编译器优化代码的原因。 - M A
我仍然看不到JLS如何将其指定为编译错误。我只看到了一个常量变量的定义。 - Paul Draper

10

byte转换为char是一种扩展和缩小的原始类型转换,如Java语言规范第5.1.4段中所述。

正如JLS所描述的那样,这是通过一个中间步骤完成的;byte通过扩展原始类型转换转换为int,然后int通过缩小原始类型转换转换为char(参见5.1.3)。

第5.2段解释了在进行赋值时何时需要进行强制转换:

如果表达式是类型为byte、short、char或int的常量表达式(§15.28):
  • 如果变量的类型是byte、short或char,并且常量表达式的值可以用变量的类型表示,则可以使用缩小原始转换。
您的变量b1确实是一个常量,但是您的变量b2不是,因此这个规则适用于b1而不适用于b2。
因此,您可以将b1赋给c,因为b1是一个常量,常量的值1适合于char,但是您不能将b2分配给c,除非进行强制转换,因为b2不是常量。

@PaulDraper 嗯,这些只是语言规范中的官方规则,它们解释了为什么一个有效而另一个是错误。最终你需要记住的是,如果是常量,你不需要进行强制类型转换。之所以在这种情况下不需要进行强制类型转换是为了方便。 - Jesper

0

嗯,这是因为byte是有符号类型而char不是,所以你需要对(2)进行显式类型转换。

c = (char)b2;

最后的语句之所以适用于1,是因为在编译之前,编译器能够确认由于转换而导致的损失不存在,因为“1”在char范围内。如果在(1)中使用“-1”与相同的最终语句,则会再次出现编译错误。

所有这些归结为有符号和无符号类型之间的类型兼容性...这需要在Java中明确完成。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接