Java只定义了带符号的整型,没有无符号的整型
应该选择合适范围的整型(int
或long
),没有必要为了节省内存而使用byte
和short
进行整数运算
各种整型能表示的最大范围小·
byte:-128 ~ 127
short: -32768 ~ 32767
int: -2147483648 ~ 2147483647
long: -9223372036854775808 ~ 9223372036854775807
1个字节存储
2个字节存储
4个字节存储
8个字节存储
public class Main { public static void main(String[] args) { int i = (100 + 200) * (99 - 88); // 3300 int n = 7 * (5 + (i - 9)); // 23072 System.out.println(i); System.out.println(n); } } >>> 3300 23072
Java还提供了++
运算和--
运算,它们可以对一个整数进行加1和减1的操作
public class Main { public static void main(String[] args) { int n = 3300; n++; // 3301, 相当于 n = n + 1; n--; // 3300, 相当于 n = n - 1; int y = 100 + (++n); // 不要这么写, 会先加然后再计算 System.out.println(y); } } >>> 3401
不建议把
++
运算混入到常规运算中
要特别注意,整数由于存在范围限制,如果计算结果超出了范围,就会产生溢出,而溢出不会出错,却会得到一个奇怪的结果
public class Main { public static void main(String[] args) { int x = 2147483640; int y = 15; int sum = x + y; System.out.println(sum); } } >>> -2147483641
要解决上面的问题,可以把int
换成long
类型,由于long
可表示的整型范围更大,所以结果就不会溢出
public class Main { public static void main(String[] args) { long x = 2147483640; int y = 15; long sum = x + y; System.out.println(sum); } } >>> 2147483655
与 && 或 || 非 !
condition ? expression1: expression2
若条件为true, 为第一个表达式的值,否则为第二个表达式的值
在计算机中,整数总是以二进制的形式表示。例如,int
类型的整数7
使用4字节表示的二进制如下:
00000000 0000000 0000000 00000111
可以对整数进行移位运算。对整数7
左移1位将得到整数14
,左移两位将得到整数28
:
int n = 7; // 00000000 0000000 0000000 00000111 int a = n << 1; // 00000000 0000000 0000000 00001110 <= 14 int b = n << 2; // 00000000 0000000 0000000 00011100 <= 28 int c = n << 28; // 01110000 0000000 0000000 00000000 <= 1879048192 int d = n << 29; // 11100000 0000000 0000000 00000000 <= -536870912
左移29位时,由于最高位变成1
,因此结果变成了负数。
类似的,对整数28进行右移,结果如下:
int n = 7; // 00000000 0000000 0000000 00000111 int a = n >> 1; // 00000000 0000000 0000000 00000011 <= 3 int b = n >> 2; // 00000000 0000000 0000000 00000001 <= 1 int c = n >> 3; // 00000000 0000000 0000000 00000000 <= 0
如果对一个负数进行右移,最高位的1
不动,结果仍然是一个负数:
int n = -536870912; int a = n >> 1; // 11110000 0000000 0000000 00000000 <= -268435456 int b = n >> 2; // 10111000 0000000 0000000 00000000 <= -134217728 int c = n >> 28; // 10000000 0000000 0000000 00000001 <= -2 int d = n >> 29; // 10000000 0000000 0000000 00000000 <= -1
还有一种不带符号的右移运算,使用>>>
,它的特点是符号位跟着动,因此,对一个负数进行>>>
右移,它会变成正数,原因是最高位的1
变成了0
:
int n = -536870912; int a = n >>> 1; // 01110000 0000000 0000000 00000000 <= 1879048192 int b = n >>> 2; // 00111000 0000000 0000000 00000000 <= 939524096 int c = n >>> 29; // 00000000 0000000 0000000 00000111 <= 7 int d = n >>> 31; // 00000000 0000000 0000000 00000001 <= 1
对byte
和short
类型进行移位时,会首先转换为int
再进行位移。
仔细观察可发现,左移实际上就是不断地×2,右移实际上就是不断地÷2。
位运算是按位进行与、或、非和异或的运算。
与运算的规则是,必须两个数同时为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
虚线会丢失精度
在运算过程中,如果参与运算的两个数类型不一致,那么计算结果为较大类型的整型。例如,short
和int
计算,结果总是int
,原因是short
首先自动被转型为int
public class Main { public static void main(String[] args) { 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
的两个高位字节直接被扔掉,仅保留了低位的两个字节
public class Main { public static void main(String[] args) { int i1 = 1234567; short s1 = (short) i1; System.out.println(s1); int i2 = 1345678; short s2 = (short) i2; System.out.println(s2); } } >>> -10617 -30578
通过(cast) 实现这个操作, 括号中是想要转换的目标类型
double x = 9.997; int nx = (int) x; // 9