java中整型数据(byte、short、int、long)溢出的现象及原理

简介: java中整型数据(byte、short、int、long)溢出的现象及原理

我们都知道Java中基本数据类型中,整型的有byteshortintlong,依次占用内存空间是1、2、4、8个字节,它们的取值范围如下:

类型 字节数 取值范围
byte 1 [-128,127]
short 2 [-32768,32767]
int 4 [-2147483648,2147483647]
long 8 [-9223372036854775808,9223372036854775807]

既然数据有范围,那么就会存在数据溢出的问题,那么我们看下数据溢出了会是怎样的?

byte数据溢出现象

测试代码如下:

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)结果

我们接着看下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]

接下来我们看另一个例子,代码如下:

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);

output:

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的结果都是它们取值范围的最小值,相当于开启了取值范围的下一个循环。

参考

Java中,为什么byte类型的取值范围为-128~127?

【思考笔记】byte数据溢出的现象及原理

相关文章
|
12月前
|
Java
java 读取文件 获取byte[]字节 并执行Gzip的压缩和解压
java 读取文件 获取byte[]字节 并执行Gzip的压缩和解压
114 0
|
17天前
|
机器学习/深度学习 算法
让星星⭐月亮告诉你,HashMap之tableSizeFor(int cap)方法原理详解(分2的n次幂和非2的n次幂两种情况讨论)
`HashMap` 的 `tableSizeFor(int cap)` 方法用于计算一个大于或等于给定容量 `cap` 的最小的 2 的幂次方值。该方法通过一系列的无符号右移和按位或运算,逐步将二进制数的高位全部置为 1,最后加 1 得到所需的 2 的幂次方值。具体步骤包括: 1. 将 `cap` 减 1,确保已经是 2 的幂次方的值直接返回。 2. 通过多次无符号右移和按位或运算,将最高位 1 后面的所有位都置为 1。 3. 最终加 1,确保返回值为 2 的幂次方。 该方法保证了 `HashMap` 的数组容量始终是 2 的幂次方,从而优化了哈希表的性能。
30 1
|
4月前
|
Java Apache Maven
Java:commons-codec实现byte数组和16进制字符串转换
在上述代码中,`Hex.encodeHexString(bytes)`用于将byte数组转换为16进制字符串,`Hex.decodeHex(hexString)`用于将16进制字符串转换为byte数组。
47 0
|
4月前
|
Java Apache Maven
Java:commons-codec实现byte数组和16进制字符串转换
在上述代码中,`Hex.encodeHexString(bytes)`用于将byte数组转换为16进制字符串,`Hex.decodeHex(hexString)`用于将16进制字符串转换为byte数组。
74 0
|
6月前
|
SQL 关系型数据库 MySQL
PostgreSQL【异常 01】java.io.IOException:Tried to send an out-of-range integer as a 2-byte value 分析+解决
PostgreSQL【异常 01】java.io.IOException:Tried to send an out-of-range integer as a 2-byte value 分析+解决
410 1
|
存储 自然语言处理 Java
Java_9_为何要将_String_的底层实现由_char[]_改成了_byte[]_?
Java_9_为何要将_String_的底层实现由_char[]_改成了_byte[]_?
|
存储 Java 计算机视觉
java 之byte
当涉及到处理数据时,Java 提供了多种数据类型,其中包括 `byte` 类型。在本文中,我们将深入探讨 Java 中的 `byte` 数据类型,了解它的特点、用途以及在编程中的实际应用。
|
6月前
|
数据采集 分布式计算 数据处理
Dataphin常见问题之与指定类型int不兼容如何解决
Dataphin是阿里云提供的一站式数据处理服务,旨在帮助企业构建一体化的智能数据处理平台。Dataphin整合了数据建模、数据处理、数据开发、数据服务等多个功能,支持企业更高效地进行数据治理和分析。
|
6月前
|
SQL 流计算 OceanBase
OceanBase CDC从热OB库采集过来的Tinyint(1)类型会默认转换成Boolean,请教一下,如果想转换成int类型,有什方法么?
【2月更文挑战第25天】OceanBase CDC从热OB库采集过来的Tinyint(1)类型会默认转换成Boolean,请教一下,如果想转换成int类型,有什方法么?
152 3
|
28天前
|
Python
[oeasy]python036_数据类型有什么用_type_类型_int_str_查看帮助
本文回顾了Python中`ord()`和`chr()`函数的使用方法,强调了这两个函数互为逆运算:`ord()`通过字符找到对应的序号,`chr()`则通过序号找到对应的字符。文章详细解释了函数参数类型的重要性,即`ord()`需要字符串类型参数,而`chr()`需要整数类型参数。若参数类型错误,则会引发`TypeError`。此外,还介绍了如何使用`type()`函数查询参数类型,并通过示例展示了如何正确使用`ord()`和`chr()`进行转换。最后,强调了在函数调用时正确传递参数类型的重要性。
19 3