Java之整数运算
Java的整数运算遵循四则运算规则,可以使用任意嵌套的小括号。四则运算规则和初等数学一致。例如:
1 2 3 4 5 6 7 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); } } |
输出
1 2 | 3300 23072 |
整数运算的数值不但是精确的,而且整数运算永远是精确的,即使是出发,因为两个整数相除只得到结果的整数部分,不进行四舍五入
1 | int x= 11 / 3 ; |
求余运算
1 | int x= 11 % 3 ; |
整数除法对于被除数为0运行时报错,但编译时不报错
溢出
整数由于存在范围限制,如果计算结果超出了范围,就会产生溢出,而溢出不会报错而会得到一个奇怪的结果。
1 2 3 4 5 6 7 8 | public class Main { public static void main(String[] args) { int x= 2147483640 ; int y= 15 ; int sum=x+y; System.out.println(sum); } } |
运行结果
1 | - 2147483641 |
要解释上述结果,我们把整数2147483640和15换成二进制做加法
0111 1111 1111 1111 1111 1111 1111 1000
+ 0000 0000 0000 0000 0000 0000 0000 1111
1000 0000 0000 0000 0000 0000 0000 0111
由于最高位计算结果为1,因此加法结果变成了一个负数
要解决上面的文件,可以把int换成long类型,由于long可表示的整型范围更大,所以结果不会溢出
1 2 3 4 5 6 7 8 | public class Main { public static void main(String[] args) { long x= 2147483640 ; long y= 15 ; long sum=x+y; System.out.println(sum); } } |
还有一种简写的运算符,即+=,-=,*=,/=,使用方法如下
1 2 | n+= 100 ; //相当于n=n+100 n-= 100 ; //相当于n=n-100 |
自增/自减
Java还提供了++
运算和--
运算,它们可以对一个整数进行加1和减1的操作:
1 2 3 4 5 6 7 8 9 | public class Main { public static void main(String[] args) { int n= 100 ; n++; System.out.println(n); n--; System.out.println(n); } } |
注意++
写在前面和后面计算结果是不同的,++n
表示先加1再引用n,n++
表示先引用n再加1。不建议把++
运算混入到常规运算中,容易自己把自己搞懵了。
移位运算
在计算机中,整数总是以二进制的形式表示。例如,int
类型的整数7
使用4字节表示的二进制如下:
00000000 00000000 00000000 00000111
可以对整数进行移位运算。对整数7左移1位将得到整数14,左移2位将得到整数28
1 2 3 4 5 | 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 |
左移29位时,由于最高位变成了1,因此结果变成了负数
类似地对证书7进行右移结果如下
1 2 3 4 | int n = 7 ; // 00000000 00000000 00000000 00000111 = 7 int a = n >> 1 ; // 00000000 00000000 00000000 00000011 = 3 int b = n >> 2 ; // 00000000 00000000 00000000 00000001 = 1 int c = n >> 3 ; // 00000000 00000000 00000000 00000000 = 0 |
如果对一个负数进行右移,最高位1不动,结果仍然是一个负数
1 2 3 4 | int n = - 536870912 ; int a = n >> 1 ; // 11110000 00000000 00000000 00000000 = -268435456 int b = n >> 2 ; // 10111000 00000000 00000000 00000000 = -134217728 int c = n >> 28 ; // 11111111 11111111 11111111 11111110 = -2 |
还有一种不带符号的右移运算,使用>>>
,它的特点是符号位跟着动,因此,对一个负数进行>>>
右移,它会变成正数,原因是最高位的1
变成了0
:
1 2 3 4 5 | 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 |
对byte和short类型进行位移时,会首先转换为int再进行位移
左移实际上就是不断地*2,右移实际上就是不断地/2
位运算
位运算是按位进行与,或,非和异或的运算。
与运算的规则是,必须两个数同时为1,结果才为1
1 2 3 4 | n= 0 & 0 ; //0 n= 0 & 1 ; //0 n= 1 & 0 ; //0 n= 1 & 1 ; //1 |
或运算的规则是,只要任意一个为1,结果就为1
1 2 3 4 | n = 0 | 0 ; // 0 n = 0 | 1 ; // 1 n = 1 | 0 ; // 1 n = 1 | 1 ; // 1 |
非运算的规则是,0和1呼唤
1 2 | n = ~ 0 ; // 1 n = ~ 1 ; // 0 |
异或运算的规则是,如果两个数不同,结果为1,否则为0
1 2 3 4 | n = 0 ^ 0 ; // 0 n = 0 ^ 1 ; // 1 n = 1 ^ 0 ; // 1 n = 1 ^ 1 ; // 0 |
对于两个整数的运算,实际上就是按位对齐,然后依次对每一位进行运算。例如
1 2 3 4 5 6 7 | public class Main { public static void main(String[] args) { int i = 167776589 ; int n = 167776512 ; System.out.println(i&n); } } |
运行结果
1 | 167776512 |
上述按位与运算实际上可以看作两个整数表示的IP地址10.0.17.77
和10.0.17.0
,通过与运算,可以快速判断一个IP是否在给定的网段内。
运算优先级
在Java的计算表达式中,运算优先级从高到低依次是:
()
!
~
++
--
*
/
%
+
-
<<
>>
>>>
&
|
+=
-=
*=
/=
记不住也没关系,只需要加括号就可以保证运算的优先级正确。
类型的自动提升与强制转型
在运算过程中,如果参与运算的两个数类型不一致,那么计算结果为较大类型的整型。例如,short
和int
计算,结果总是int
,原因是short
首先自动被转型为int
:
1 2 3 4 5 6 7 8 | 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
:
1 2 | int i= 12345 ; short s = ( short ) i; //12345 |
超出范围的强制转型会得到错误的结果,原因是转型时,int的两个高位直接直接被扔掉,仅保留了低位的两个字节。
举例说明
1 2 3 4 5 6 7 8 9 10 | public class Main { public static void main(String[] args) { int i1 = 1234567 ; short s1 = ( short ) i1; // -10617 System.out.println(s1); int i2 = 12345678 ; short s2 = ( short ) i2; // 24910 System.out.println(s2); } } |
结果
1 2 | - 10617 24910 |
为什么结果是-10617和24910呢
首先把1234567转换成二进制并且使用8位分割成4份
00000000 00010010 11010110 10000111
强制转换成short类型或高位被抛弃留下低位两个字节
11010110 10000111
最高位为1是负数,负数是以补码的形式存储在计算机内需要转换成原码
原码等于补码-1后除符号位取反
补码-1结果
11010110 10000110
除符号位取反得到原码
10101001 01111001
最高位为1所以是负数101001 01111001即-10617
同理计算12345678去掉高两位后剩下的最高位为0是正数则补码和原码是一样的
练习
计算自然数之和
1 2 3 4 5 6 7 8 9 10 | public class Main { public static void main(String[] args) { int n= 100 ; int sum= 0 ; for ( int i= 1 ;i<=n;i++) { sum=sum+i; } System.out.println(sum); } } |
小结
整数运算的结果永远都是精确的
运算结果会自动提升
可以强制转型,但超出范围的强制转型会得到错误的结果
应该选择合适范围的整型(int
或long
),没有必要为了节省内存而使用byte
和short
进行整数运算。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!