我有这段代码:
public class First
{
public static void main(String[] args)
{
byte b=50;
byte c=b*2; //Error
byte d=50*2; //d=100
byte e=(byte)258; //e=258%256;
byte f=(byte)128; //f=128%256;
}
}
byte
的算术表达式都是第一个
升级到int
然后执行。所以我期待
d=50*2
也报告错误,因为50*2
的结果是int
值,我们将它存储在byte
中,没有任何显式类型转换。
如果Java隐式执行转换,为什么c=b*2
会报告
错误?byte
变量的范围内,那么我必须明确键入
将其转换为byte
,将存储的值为值
模256(字节大小)。因此,为什么byte f=(byte)128
会返回
-128
?自128 % 256 = 128
起,我所期望的是f=128
,但它会返回-128
。为什么?非常感谢。
答案 0 :(得分:2)
这是因为50*2;
将在编译时解析,而b*2;
将在运行时解析。因此,在编译时,Java编译器确保50*2;
的结果为100.但是在b*2;
的情况下,正如您还提到算术运算的结果是int
和编译器无法确定结果是否超出byte
限制,因此它会抱怨并希望您通过投射或更改类型来确定相关内容。
您可以使用javap -v Test.class
进行验证。见下文:
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: bipush 100
2: istore_1
3: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
6: iload_1
7: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
10: return
LineNumberTable:
line 4: 0
line 5: 3
line 6: 10
关于你的第二个问题,@ Eran已经解释过使用128和258的位表示,你可以从JLS §5.1.3. Narrowing Primitive Conversion进一步阅读
将有符号整数缩小转换为整数类型T. 简单地丢弃除n个最低位之外的所有位,其中n是数字 用于表示类型T的位数。除了可能的丢失 有关数值大小的信息,这可能会导致 结果值的符号与输入符号不同 值。
答案 1 :(得分:1)
关于第二个问题,当你向下转换数字类型时,输入的低位用于初始化输出。
因此,int
128
,其二进制表示为0......010000000
成为字节10000000
(取低8位),即-128
另一方面,258
为0........01000000010
,当你取低8位时,你会得到00000010
,即2。
答案 2 :(得分:1)
除了分配之外,还有另一个地方可能会发生某些类型的转换:即在表达式中。
要了解原因,请考虑以下事项。在表达式中,精度 中间值所需的有时会超过任一操作数的范围。
例如,检查以下表达式:
byte a = 40;
byte b = 50;
byte c = 100;
int d = a * b / c;
中间项a * b
的结果很容易超出其任一字节操作数的范围。为了处理此类问题,Java在评估表达式时会自动将每个byte
,short
或char
操作数提升为int
。
这意味着子表达式a*b
使用整数而不是字节来执行。因此,2,000,即中间表达式50 * 40的结果是合法的,即使a和b都被指定为类型字节。
与自动促销一样有用,它们会导致混乱的编译时间 错误。
例如,这个看似正确的代码会导致问题:
byte b = 50;
b = b * 2; // Error! Cannot assign an int to a byte!
代码尝试将50 * 2(完全有效的byte
值)存储回byte
变量。但是,由于在计算表达式时操作数会自动提升为int
,因此结果也会提升为int
。因此,表达式的结果现在是int
类型,如果不使用byte
,则无法将其分配给cast
。
即使在这种特殊情况下,所分配的值仍然适合目标类型,也是如此。 如果您了解溢出的后果,则应使用显式转换,例如
byte b = 50;
b = (byte)(b * 2);
产生正确的值100。