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数据溢出的现象及原理

相关文章
|
2月前
|
存储 Java 关系型数据库
高效连接之道:Java连接池原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。频繁创建和关闭连接会消耗大量资源,导致性能瓶颈。为此,Java连接池技术通过复用连接,实现高效、稳定的数据库连接管理。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接池的基本操作、配置和使用方法,以及在电商应用中的具体应用示例。
86 5
|
25天前
|
监控 Java API
探索Java NIO:究竟在哪些领域能大显身手?揭秘原理、应用场景与官方示例代码
Java NIO(New IO)自Java SE 1.4引入,提供比传统IO更高效、灵活的操作,支持非阻塞IO和选择器特性,适用于高并发、高吞吐量场景。NIO的核心概念包括通道(Channel)、缓冲区(Buffer)和选择器(Selector),能实现多路复用和异步操作。其应用场景涵盖网络通信、文件操作、进程间通信及数据库操作等。NIO的优势在于提高并发性和性能,简化编程;但学习成本较高,且与传统IO存在不兼容性。尽管如此,NIO在构建高性能框架如Netty、Mina和Jetty中仍广泛应用。
37 3
|
25天前
|
安全 算法 Java
Java CAS原理和应用场景大揭秘:你掌握了吗?
CAS(Compare and Swap)是一种乐观锁机制,通过硬件指令实现原子操作,确保多线程环境下对共享变量的安全访问。它避免了传统互斥锁的性能开销和线程阻塞问题。CAS操作包含三个步骤:获取期望值、比较当前值与期望值是否相等、若相等则更新为新值。CAS广泛应用于高并发场景,如数据库事务、分布式锁、无锁数据结构等,但需注意ABA问题。Java中常用`java.util.concurrent.atomic`包下的类支持CAS操作。
62 2
|
2月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
2月前
|
Java
Java之CountDownLatch原理浅析
本文介绍了Java并发工具类`CountDownLatch`的使用方法、原理及其与`Thread.join()`的区别。`CountDownLatch`通过构造函数接收一个整数参数作为计数器,调用`countDown`方法减少计数,`await`方法会阻塞当前线程,直到计数为零。文章还详细解析了其内部机制,包括初始化、`countDown`和`await`方法的工作原理,并给出了一个游戏加载场景的示例代码。
Java之CountDownLatch原理浅析
|
2月前
|
Java 索引 容器
Java ArrayList扩容的原理
Java 的 `ArrayList` 是基于数组实现的动态集合。初始时,`ArrayList` 底层创建一个空数组 `elementData`,并设置 `size` 为 0。当首次添加元素时,会调用 `grow` 方法将数组扩容至默认容量 10。之后每次添加元素时,如果当前数组已满,则会再次调用 `grow` 方法进行扩容。扩容规则为:首次扩容至 10,后续扩容至原数组长度的 1.5 倍或根据实际需求扩容。例如,当需要一次性添加 100 个元素时,会直接扩容至 110 而不是 15。
Java ArrayList扩容的原理
|
2月前
|
Java
byte加byte居然是int了
为什么在Java中,byte加byte的结果不是byte,而是int?本文将带你从Java语言规范和JVM规范层面研究该问题。
70 3
byte加byte居然是int了
|
2月前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
76 2
|
2月前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
64 5
|
2月前
|
算法 Java 数据库连接
Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性
本文详细介绍了Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性。连接池通过复用数据库连接,显著提升了应用的性能和稳定性。文章还展示了使用HikariCP连接池的示例代码,帮助读者更好地理解和应用这一技术。
65 1