负的字符值 JAVA

5
为什么会发生以下情况:
char p = 0;
p--;
System.out.println(p);

结果 65535

为什么没有出现编译错误或运行时异常? 我本来以为字符不能是负数。相反它从倒数开始倒数。 提前感谢。


这只是一个好的旧无符号短整型。 - Jessie Lesbian
2个回答

18
因为语言规范规定原始类型的算术运算是模2^width,所以-1char中变成了2^16-1。在整数操作部分中指出:

内置整数运算符不以任何方式指示溢出或下溢。

所以禁止抛出异常。对于特定使用的后缀递减运算符,其行为在15.14.3中有明确规定。
否则,将1的值从变量的值中减去,并将差存回变量。在减法之前,对值1和变量的值执行二进制数值提升(§5.6.2)。必要时,将差通过缩小基本转换(§5.1.3)和/或装箱转换(§5.1.7)转换为变量的类型,然后再存储。后缀递减表达式的值是存储新值之前变量的值。
二进制数值提升将值和1都转换为int(因为这里的类型是char),因此您将获得中间结果-1作为int,然后执行缩小基本转换:
有符号整数到整型T的缩小转换只需丢弃所有低于n阶位的位数,其中n是用于表示类型T的位数。除可能会导致数值大小信息的丢失外,这还可能导致所得值的符号与输入值的符号不同。

这段代码会导致char值为0xFFFF(由于Java对于其带符号整数类型采用二进制补码表示法,该规范在取反运算符中有明确说明):

对于整数值,取反等同于从零开始减去该值。 Java编程语言使用二进制补码表示整数,而二进制补码值的范围不对称,因此对最大负整数或长整型数进行取反将导致相同的最大负数。在这种情况下会发生溢出,但不会抛出异常。对于所有整数值x,-x等于(~x)+1。

对于超出范围结果的一般环绕行为,以乘法运算符的规范为例:

如果整数乘法溢出,则结果是以某个足够大的二进制补码格式表示的数学乘积的低位比特。因此,如果发生溢出,则结果的符号可能与两个操作数值的数学乘积的符号不同。
在整数加法规范中出现类似的短语,并且要求减法满足 a - b == a + (-b),因此溢出行为遵循。

你有可以引用的参考资料吗? - donfede
给我一分钟去谷歌搜索一下,我手头没有规格说明。 - Daniel Fischer

1
因为这就是Java语言的定义。运行时不会在每个操作中检查边界(可能是因为这样做非常昂贵)。它只会溢出或下溢。

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