整数运算
四则运算
Java 的整数运算遵循四则运算规则,可以使用任意嵌套的小括号。
public class Main {
public static void main(String[] args) {
// 3
int i = (1 + 2) * (99 - 98);
System.out.println(i);
}
}
整数运算只能返回整数,所以两数相除,除不尽时返回的是结果的整数部分:
// 1
int x = 15 / 10;
求余运算:
// 5
int y = 15 % 10;
溢出
要特别注意,整数由于存在范围限制,如果计算结果超出了范围,就会产生溢出,且溢出不会出错。
int x = 2147483640;
int y = 15;
int sum = x + y;
// -2147483641
System.out.println(sum);
自增 / 自减
Java 还提供了 ++ 运算和 -- 运算,它们可以对一个整数进行加 1 和减 1 的操作:
int n = 0;
// 1, 相当于 n = n + 1
n++;
// 0, 相当于 n = n - 1
n--;
位移运算
在计算机中,整数总是以二进制的形式表示。例如,int类型的整数7使用4字节表示的二进制如下:
00000000 0000000 0000000 00000111
可以对整数进行移位运算。对整数7左移1位将得到整数14,左移两位将得到整数28,左移29位时,由于最高位变成1,因此结果变成了负数:
int n = 7; // 00000000 00000000 00000000 00000111 = 7
int a = n << 1; // 00000000 00000000 00000000 00001110 = 14
int b = n << 2; // 00000000 00000000 00000000 00011100 = 28
int c = n << 28; // 01110000 00000000 00000000 00000000 = 1879048192
int d = n << 29; // 11100000 00000000 00000000 00000000 = -536870912\
还有一种无符号的右移运算,使用>>>,它的特点是不管符号位,右移后高位总是补0,因此,对一个负数进行>>>右移,它会变成正数,原因是最高位的1变成了0:
int n = -536870912;
int a = n >>> 1; // 01110000 00000000 00000000 00000000 = 1879048192
int b = n >>> 2; // 00111000 00000000 00000000 00000000 = 939524096
int c = n >>> 29; // 00000000 00000000 00000000 00000111 = 7
int d = n >>> 31; // 00000000 00000000 00000000 00000001 = 1
位运算
位运算是按位进行与、或、非和异或的运算。
与运算的规则是,必须两个数同时为1,结果才为1:
n = 0 & 0; // 0
n = 0 & 1; // 0
n = 1 & 0; // 0
n = 1 & 1; // 1
或运算的规则是,只要任意一个为1,结果就为1:
n = 0 | 0; // 0
n = 0 | 1; // 1
n = 1 | 0; // 1
n = 1 | 1; // 1
非运算的规则是,0和1互换:
n = ~0; // 1
n = ~1; // 0
异或运算的规则是,如果两个数不同,结果为1,否则为0:
n = 0 ^ 0; // 0
n = 0 ^ 1; // 1
n = 1 ^ 0; // 1
n = 1 ^ 1; // 0
对两个整数进行位运算,实际上就是按位对齐,然后依次对每一位进行运算。例如:
public class Main {
public static void main(String[] args) {
int i = 167776589; // 00001010 00000000 00010001 01001101
int n = 167776512; // 00001010 00000000 00010001 00000000
System.out.println(i & n); // 167776512
}
}
运算优先级
()
!
~
++
--
*
/
%
+
-
<<
>>
>>>
&
|
+=
-=
*=
/=
记不住也没关系,只需要加括号就可以保证运算的优先级正确。
类型自动提升与强制转型
在运算过程中,如果参与运算的两个数类型不一致,那么计算结果为较大类型的整型。例如,short和int计算,结果总是int,原因是short首先自动被转型为int:
public static void typeConversion() {
short s = 1234;
int i = 123456;
int x = s + i; // s自动转型为int
short y = s + i; // 编译错误!
}
也可以将结果强制转型,即将大范围的整数转型为小范围的整数。强制转型使用(类型),例如,将int强制转型为short:
int i = 12345;
short s = (short) i; // 12345
要注意,超出范围的强制转型会得到错误的结果,原因是转型时,int的两个高位字节直接被扔掉,仅保留了低位的两个字节。
小结
- 整数运算的结果永远是精确的;
- 运算结果会自动提升;
- 可以强制转型,但超出范围的强制转型会得到错误的结果;
- 应该选择合适范围的整型(int或long),没有必要为了节省内存而使用byte和short进行整数运算。