java中整型数据(byte、short、int、long)溢出的现象及原理
我们都知道Java中基本数据类型中,
类型 | 字节数 | 取值范围 |
---|---|---|
byte | 1 | [-128,127] |
short | 2 | [-32768,32767] |
int | 4 | [-2147483648,2147483647] |
long | 8 | [-9223372036854775808,9223372036854775807] |
既然数据有范围,那么就会存在数据溢出
的问题,那么我们看下数据溢出了会是怎样的?
byte数据溢出现象
测试代码:
package com.luozhe.base;
public class Test1 {
public static void main(String[] args){
byte b = Byte.MAX_VALUE;// 127
System.out.println("Byte.MAX_VALUE:" + b);
b = (byte) (b + 1);// 由于整型数据会自动向上转型为int,所以这里需要强转。
System.out.println("Byte.MAX_VALUE+1:" + b);// -128
}
}
这里我们给byte的最大值加1,然后再赋值给byte类型,输出如下:
Byte.MAX_VALUE:127
Byte.MAX_VALUE+1:-128
可以看到输出的是-128
,跟我们想象的有点不太一样,接下来我们分析下原理。
原理分析:
我们知道,整型数据在计算机中都是用二进制表示的。这里我们继续拿byte进行举例,比如说1的二进制表示为0000 0001,-1的二进制表示为1000 0001,最高位是符号位,1表示负数,0表示正数。
我们知道byte类型占一个字节,也就是8bit,那么它应该能表示128个数字;除去最高位的符号位后,还有7个bit来表示数字,也就是[0,127]这个范围,共128个数字;如果加上符号位,那么byte可以表示的数的范围是[-127,-0]和[0,127],-0和0表示的数据相同,我们进行合并,所以范围应该是[-127,127],而java规定的范围是[-128,127],-128怎么表示的。
其实-128就是用-0来表示的,二进制的补码表示就是1000 0000。
接下来我们说下几个基本概念:原码、反码和补码。
原码、反码和补码
原码:就是数据的二进制表示形式,最高位是符号位,1表示负数,0表示正数。
反码:正数的反码跟原码相同;负数的反码是在原码的基础上,符号位不变,其余各位取反,1变0,0变1。
补码:正数的补码跟原码相同;负数的补码是在其反码的基础上加1。
比如说,10的原码是0000 1010,由于它是正数,所以它的反码和补码均与原码相同。 -10的原码是1000 1010;它的反码是在原码基础上,符号位不变,其余位数取反,转换后的反码是1111 0101;补码是在反码的基础上+1,转换后的补码是1111 0110。
加法运算过程拆解
在计算机的二进制计算中,减法运算
也会转化为加法运算
来计算。
对于10-10=0
的这个运算,在实际计算过程中,会将10 - 10
的操作转化为10 + (-10)
。接下来我们看下具体的运算过程:
数据类型 | 10 | -10 |
---|---|---|
原码 | 0000 1010 |
1000 1010 |
反码 | 0000 1010 |
1111 0101 |
补码 | 0000 1010 |
1111 0110 |
得到对应的补码之后,我们对10
和-10
的补码进行加法操作:
+ 0000 1010
——————————— = 0000 0000
1111 0110
我们知道补码0000 0000
对应的原码也为0000 0000
,所以可以得出10 - 10 = 0
。
验证(byte)(127+1)的运算过程
数据类型 | 127 | 1 |
---|---|---|
原码 | 0111 1111 |
0000 0001 |
反码 | 0111 1111 |
0000 0001 |
补码 | 0111 1111 |
0000 0001 |
得到对应的补码之后,我们对相应的补码进行加法操作:
+ 0111 1111
——————————— = 1000 0000
0000 0001
这里我们得到了1000 0000这个补码,而这个补码对应的数据就是-128,这是一个特例。
这里需要注意的是,因为使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示。(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000], 这是不正确的)。
byte越界后的数据其实是循环展示[-128,127]
package com.luozhe.base;
public class Test1 {
public static void main(String[] args){
byte b = (byte) (Byte.MAX_VALUE + 255);
System.out.println("Byte.MAX_VALUE+255:" + b);
b = (byte) (Byte.MAX_VALUE + 256);
System.out.println("Byte.MAX_VALUE+256:" + b);
b = (byte) (Byte.MAX_VALUE + 257);
System.out.println("Byte.MAX_VALUE+257:" + b);
}
}
输出结果:
Byte.MAX_VALUE+255:126
Byte.MAX_VALUE+256:127
Byte.MAX_VALUE+257:-128
一个字节可表示的数据个数是256,结合前面(byte)(127 +1)
的结果是-128
,我们可以得出一个结论,越界后的数据会以byte
的取值范围为一个单元,一直循环下去。
其他整型:short、int、long
整型的计算规则都是一样的,同理可得,其他的整型(short、int、long)也有同样的现象。测试代码如下:
short s = Short.MAX_VALUE;
System.out.println("Short.MAX_VALUE:" + s);
s = (short) (s + 1);
System.out.println("Short.MAX_VALUE+1:" + s);
int i = Integer.MAX_VALUE;
System.out.println("Integer.MAX_VALUE=" + i);
i = i + 1;
System.out.println("Integer.MAX_VALUE+1=" + i);
long l = Long.MAX_VALUE;
System.out.println("Long.MAX_VALUE=" + l);
l = l + 1;
System.out.println("Long.MAX_VALUE+1=" + l);
输出结果:
Short.MAX_VALUE:32767
Short.MAX_VALUE+1:-32768
Integer.MAX_VALUE=2147483647
Integer.MAX_VALUE+1=-2147483648
Long.MAX_VALUE=9223372036854775807
Long.MAX_VALUE+1=-9223372036854775808
可以看出,它们取值范围的最大值+1
的结果都是它们取值范围的最小值
转自:https://blog.csdn.net/qq_26287435/article/details/105923375
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】