这个循环将无限期地继续:
char a = 100;
for(a=100; a>=0;--a)
System.out.println(a);
是否会发生这种情况,因为 a 被提升为算术运算的 int 值并从 16 位 char 值扩大到 32 位,因此将始终保持正数?
它确实会无限循环——你所说的原因很接近。发生这种情况是因为a
不能表示任何不满足的数字-是a >= 0
无char
符号的。算术下溢在 Java 中定义明确且未指明。请参阅规范的以下相关部分。
整数运算符不以任何方式指示上溢或下溢。
这意味着除了比较值之外没有溢出/下溢的迹象......例如,如果a
<= --a
,那么这意味着发生了下溢。
在减法之前,对值 1 和变量的值执行二进制数字提升(第 5.6.2 节)。如有必要,通过缩小原始转换(第 5.1.3 节)和/或在存储变量之前对其类型进行装箱转换(第 5.1.7 节)来缩小差异。前缀递减表达式的值是存储新值后变量的值。
因此,我们可以看到这里有两个主要步骤:二进制数字提升,然后是缩小原始转换。
加宽原语转换(第 5.1.2 节)适用于转换以下规则指定的一个或两个操作数:
- 如果任一操作数的类型为
double
,则将另一个转换为double
。- 否则,如果任一操作数的类型为
float
,则将另一个转换为float
。- 否则,如果任一操作数的类型为
long
,则将另一个转换为long
。- 否则,两个操作数都转换为 type
int
。
我们可以看到递减表达式与a
视为一起工作int
,因此执行了扩大转换。这允许它表示值-1。
缩小原语转换可能会丢失有关数值整体大小的信息,也可能会丢失精度和范围。
...
有符号整数到整数类型 T 的窄化转换只会丢弃除n 个最低位之外的所有位,其中n是用于表示类型 T 的位数。此外,可能会丢失有关数值大小的信息,这可能会导致结果值的符号与输入值的符号不同。
仅保留n 个最低位意味着仅保留int
表达式的最低 16 位a - 1
。由于-1这里是0b11111111 11111111 11111111 11111111,所以只保存低位的0b11111111 11111111。由于char
是无符号的,所有这些位都对结果有贡献,给出65535。
注意到这里的东西了吗?本质上,这一切都意味着 Java 整数运算是模块化的;在这种情况下,模数是2^16或65536,因为char
它是 16 位数据类型。-1 (mod 65536) ≡ 65535,所以减量会回绕。
没有。char
值是无符号的 - 当它们低于 0 时,它们会回到 65535 左右。
交换- 然后它会工作char
。byte
正如其他人所说,char
Java 中的类型是无符号的,所以a >= 0
总是如此。当a
达到 0 然后再次递减时,它变为 65535。如果你只是想反常,你可以这样编写循环以在 101 次迭代后终止:
char a = 100;
for(a=100; a<=100;--a)
System.out.println(a);
然后,代码审查员可能会因为写出如此可怕的东西而让你心碎。:)