为什么会发生这种情况:
char a = '\uffff'; //Highest value that char can take - 65535
byte b = (byte)a; //Casting a 16-bit value into 8-bit data type...! Isn't data lost here?
char c = (char)b; //Let's get the value back
int d = (int)c;
System.out.println(d); //65535... how?
基本上,我看到char
是16位。因此,如果将其转换为byte
,为什么没有数据丢失? (在转换为int之后,值相同)
提前感谢您回答我这个无知的小问题。 :P
编辑:哇,发现我的原始输出实际上按预期进行了,但我刚刚更新了上面的代码。基本上,将一个字符强制转换为一个字节,然后将其强制转换为char,并保留其原始的2字节值。这是怎么发生的?答案 0 :(得分:24)
正如trojanfoe所述,您对代码结果的混淆部分是由于签名扩展。我会尝试添加更详细的解释,这可能有助于您的困惑。
char a = '\uffff';
byte b = (byte)a; // b = 0xFF
正如您所指出的,这会导致信息丢失。这被认为是narrowing conversion。将char转换为字节“只丢弃除n个最低位之外的所有位”
结果是:0xFFFF -> 0xFF
char c = (char)b; // c = 0xFFFF
将字节转换为char被视为special conversion。它实际上执行两次转换。首先,字节是SIGN扩展的(新的高阶位从旧符号位复制)到int(正常的加宽转换)。其次,int转换为具有缩小转换的char
结果是:0xFF -> 0xFFFFFFFF -> 0xFFFF
int d = (int)c; // d = 0x0000FFFF
将char转换为int被视为widening conversion。当char类型扩展为整数类型时,它是ZERO扩展(新的高位设置为0)。
结果是:0xFFFF -> 0x0000FFFF
。打印时,这将为您提供65535。
我提供的三个链接是有关原始类型转换的官方Java语言规范详细信息。我强烈建议你看看。它们并不是非常冗长(在这种情况下相对简单)。它详细说明了java将在幕后进行类型转换的内容。对于许多开发人员来说,这是一个常见的误解区域。如果您仍然对任何步骤感到困惑,请发表评论。
答案 1 :(得分:8)
这是sign extension。请尝试\u1234
而不是\uffff
,看看会发生什么。
答案 2 :(得分:5)
java byte
已签名。这是反直觉的。在几乎所有使用字节的情况下,程序员都希望使用无符号字节。如果一个字节直接转换为int,那么它很可能是一个错误。
这几乎在所有程序中都能正确进行转换:
int c = 0xff & b ;
根据经验,选择带符号的字节是错误的。
答案 3 :(得分:0)
你机器上有些奇怪的东西。看看Java language specification, chapter 4.2.1:
整数类型的值是 以下范围内的整数:
对于字节,从-128到127,包括
......剪掉其他人......
如果您的JVM符合标准,那么您的输出应为-1
。