类型不匹配:无法将int转换为byte。

11
我看到有人提出有关错误“类型不匹配:无法将int转换为byte”的问题。但它们大多是由涉及算术运算的原因引起的。
以下是我的情况: (当我想在Eclipse Kepler中玩比特时会发生这种情况)
//java 7 binary literals

byte a =  0b01111111; //8-bit it compiles 

byte b =  0b10000000;  //8-bit error: Type mismatch: cannot convert int to byte.                        

byte c =  (byte) 0b10000000; //8-bit it works fine if casted.

事实是,如果它是8位并且最高位是1,则编译器会报错。我想知道为什么。前缀0b表示它是一个二进制文字,那么为什么编译器将最高位视为带符号整数数字或类似的内容?
谢谢您的回答。
[编辑3:]
byte a = -128; //a = 0xFF = 11111111 (8 bits), compiler says ok.
byte b = 0b11111111; //compiler error

[编辑2:按位与运算也会触发错误]
byte a = 0b00000000;  //8 bits
a = (a&0xFF);  //gives same error: Type mismatch: cannot convert int to byte
a = (byte)(a&0xFF); //it is fine to cast

这是两张图片。第一张图片的编辑已更新,第二张图片没有描述。
3个回答

14
你的猜测是对的,这与有符号整数有关。在Java中,所有整数类型(byteshortintlong)始终是有符号的。Java使用二进制补码来存储有符号(读作“全部”)值。这基本上意味着,如果任何类型的第一位(bit)(不是字面上指定的第一位,而是存储的第一位)为1,则该数字为负数。如果为0,则为正数。
重要的第二件事是:Java中没有BYTE字面量。有int字面量和long字面量。每个写下来的数字(无论是二进制(前缀为0b)、八进制(前缀为0)、十进制(没有前缀)还是十六进制(前缀为0x))都是整数字面量,除非你附加一个L(无论是小写还是大写),它就成了long。没有办法直接写出任何shortbyte
现在,这意味着所有你列举的那些例子都先创建了一个int。你并没有创建bytes。
所以,最后一部分是,如果你尝试将int存储在byte中-不带转换或带转换,会发生什么。
如果你显式地进行类型转换,你基本上告诉Java只忽略任何不适合的位。它们将被截断-即使这改变了数值(请参见下面的示例)。
如果没有强制转换,位仍然会被切断。但是,如果它更改了值,Java不会这样做-以确保你真的知道你在做什么。
将所有这些与问题中的示例链接起来:
int 0b01111111是127
byte 0b01111111是127
-> 转换可以在没有任何溢出的情况下完成,所以Java会在没有显式转换的情况下进行转换 int 0b10000000是128
byte 0b10000000 是 -128。
-> 当进行转换时发生溢出,因此如果没有显式的强制转换,Java 将抛出错误。

1
@JohannesH. :Java 7 引入了二进制字面量。因此,在较低的版本中,它们将不可用。 - Lion
明白了。@richard 似乎是对的。这不是关于你如何指定字节的问题,而是关于你如何不指定它们以及从整数转换为字节的工作原理。请查看我的编辑答案。 - Johannes H.
1
@JohannesH。这不应该是“prepend L”,而是“append L”吗? - Dennis Meng
@DennisMeng 应该会的 ;) - Johannes H.
1
明白了。"Java 中没有 BYTE 字面量,只有 int 字面量和 long 字面量。" 这让我完全理解了整个事情。 - Weishi Z
显示剩余10条评论

3

我认为Java中的字节是有符号的,这会使得0b10000000超出范围。127将是可能的最大字节,原因在于负数的二进制补码表示。


在二进制补码表示法中,0b10000000表示为-128,在Java中仍然位于int类型的范围内。 - Weishi Z
没错,但你试图创建一个字节,因此出现了错误。类型“byte”无法保存值0b10000000。 - richard
+1 领先的方式在这里,我同意,这必须是答案。我对此添加了一些细节,请查看我的回答。 - Johannes H.
是的,缺少二进制字面量导致了这个问题。+1 - richard
我还是不明白为什么一个字节不能容纳0b10000000的值?它有8个位。它应该代表某个值,对吧?为什么会溢出? - Weishi Z
@WeishiZeng 请看我的回答。这是因为如果值存储在一个字节中,第一位是1,因此它是一个负数。如果存储在int中,第一位是零(在您的文字中没有指定),因此是一个正数。如果将整数保存到字节中,则符号将切换->这就是所谓的溢出。 - Johannes H.

2

Byte变量可以保存0b1000000的值,但是由于它们是有符号的,所以这表示整数值-128。它无法转换文字的原因是,当您将其作为没有强制类型转换的文字写入时,编译器会将其视为(int)0b10000000,这是正128的整数值。

任何大于127的整数值都超出了字节的范围,因为字节是有符号的,并且只能保存从-128到127的整数值。这就是溢出的原因(要保存128,你需要一个第九位来表示符号)。任何时候,当有符号值的最高位为1时,它表示一个负数,因此为了将像0b10000000这样的数字放入字节中,您需要在字面值中表示一个负值。例如,值-128相当于int 0b11111111111111111111111110000000,因此您需要使用该值作为字面值,或者更简单地,只需明确将其强制转换为字节,如:(byte)0b10000000


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