把字节转换成整数,是由于Java语言规则还是由于JVM?

20
byte a = 1;
byte b = 1;
byte c = a + b;

引发错误:可能会丢失精度

byte subt = a_s - a_b;
                ^
  required: byte
  found:    int
这种行为是否与JVM有关,或者它是在Java语言中定义的?
编辑:如果它是在Java语言中定义的,那么这是因为有考虑到JVM吗?
也就是说,如果Java支持“byte”数据类型,那么为什么“对byte进行操作”的结果是“int”?

byte c = a + b; 会导致错误... b+=a; 可以成功编译。为什么? - Harsh Goswami
@HarshGoswami 请查看 https://dev59.com/BGoy5IYBdhLWcg3wMLSj - Radiodef
6个回答

26
因为这是Java虚拟机的设计方式。没有指令集执行字节类型的操作。相反,用于int类型的指令集用于执行booleanbytecharshort类型的操作。
来自JVM规范 - 第2.11.1节
编译器使用Java虚拟机指令对byteshort类型的大量字面值进行编码,以在编译时或运行时将这些值符号扩展为int类型的值。使用指令将booleanchar类型的大量字面值编码为在编译时或运行时将该字面值零扩展为int类型的值。因此,对于实际类型为booleanbytecharshort的值的大多数操作都是通过操作计算类型为int的值的指令正确执行的。
该部分还指定了其中的原因:
由于Java虚拟机的一字节操作码大小,将类型编码到操作码中会对其指令集设计施加压力。如果每个类型化指令都支持Java虚拟机的所有运行时数据类型,则会有更多的指令无法表示为一个byte。可以使用单独的指令在必要时在不受支持的数据类型和受支持的数据类型之间进行转换。

要了解各种类型可用的所有指令集的详细信息,您可以查看该部分中的表格。

还有一张表格指定了实际类型与JVM计算类型之间的映射:


1
Java 还能将它们转换为 int,执行操作,然后再将它们转换回 byte,对吧?JLS 规范似乎更适用,尽管这可能解释了 JLS 中的那部分原因。 - Bernhard Barker
@PeterLawrey 那个本地代码是否与Java有关?我的意思是它可以是另一种语言。我说的对吗?我对JIT优化知之甚少。 - Rohit Jain
@Dukeling。对于 int 类型的二进制操作,结果仍然是 int 类型。最终结果不是 byte 类型,因为结果可能无法容纳在其中。JLS 可能不太适用,因为它并没有解释 JVM 的内部工作原理,而这正是 OP 想要了解的。 - Rohit Jain
@PeterLawrey。好的。那么在这种情况下使用的指令集是什么?使用哪一个? - Rohit Jain
HTM是一个有趣的话题,因为它允许JVM并发地运行同步块,而不是一次只能运行一个,并且可以在硬件上检测到冲突是否真的发生了,而无需重新编译代码来使用它。 - Peter Lawrey
显示剩余4条评论

13

JLS 5.6.2: 二进制数值提升 对此进行了解释:

使用扩展原始类型转换(§5.1.2)将操作数转换为指定类型,具体规则如下:

  • 如果其中一个操作数是 double 类型,则另一个操作数将被转换为 double 类型。

  • 否则,如果其中一个操作数是 float 类型,则另一个操作数将被转换为 float 类型。

  • 否则,如果其中一个操作数是 long 类型,则另一个操作数将被转换为 long 类型。

  • 否则,两个操作数都将被转换为 int 类型。


12

编译器正在做正确的事情。这是因为 (a + b) 的值可能超出 byte 变量所能表示的最大值。如果您使用“final”关键字告诉编译器 a、b 值不会改变,那么它将不再报错。

final byte a = 1;
final byte b = 1;
byte c = a + b;

1
byte c = a + b; 会导致错误... b+=a; 可以成功编译。为什么? - Harsh Goswami
2
复合运算符(+=)将结果强制转换,如 b = (byte) (b + a); - René

0

编译器是正确的,要么将变量声明为final,要么转换为byte类型:

byte b =  1;
byte c =  22;
byte a = (byte) (b + c);

JAVA: byte+byte = int

:)


小心下溢或上溢。 - Stephan

0

是的,这是语言规范。

加法(+)运算符。在相加时,'a' 被隐式转换为 int 类型,b 也被转换为 int 类型。因此,result 隐式地成为 int 类型。

- 运算符同理。


-1

在对任何操作数进行算术运算时,结果以此形式存储:MAX(int,operand1 type,operand2 type,...operandN type) 例如: byte a=10; byte b=20; byte c=a+b;

那么a+b的结果将以MAX(int,operand1 type,operand2 type,...operandN type)的形式存储, 在这种情况下 MAX(int,byte,byte)最大值是int,因此c将具有int值,但c已声明为byte,我们无法将int(较大)值存储到byte(较小)中。每个算术运算符都适用于相同的规则。

这就是为什么错误会说 error: incompatible types: possible lossy conversion from int to byte


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