Java中byte转int类型为什么要amp;amp;amp;amp;amp;0xFF?

2024-01-26 03:10
文章标签 java 类型 int byte amp 0xff

本文主要是介绍Java中byte转int类型为什么要amp;amp;amp;amp;amp;0xFF?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天查看代码,翻到MD5加密代码,如下:

public String getMD5(String source) throws Exception {StringBuilder sb = new StringBuilder();byte[] output = MessageDigest.getInstance("MD5").digest(source.getBytes("utf-8"));for (int i = 0; i < output.length; i++) {int c = output[i] & 0xFF;if (c < 16) {sb.append("0");}sb.append(Integer.toHexString(c));}return sb.toString();}int c = output[i] & 0xFF;if (c < 16) {sb.append("0");}sb.append(Integer.toHexString(c));}return sb.toString();}

为什么要&0xFF ?

 

各种查资料,了解到,计算机中存储都是利用二进制的补码存储的,存储数据机制:正数存储的二进制原码,负数存储的是二进制的补码。  补码是负数的绝对值反码加1。

计算机为什么用补码存储数据,当我们明白这个问题后,就可以去理解另一个衍生问题——数据溢出

首先我们看一段数据溢出的Java代码:

/*char是无符号数,16位存储,表示范围是0~2^16-1(即0~65535)*/
char ch = Character.MAX_VALUE; // ch为65535
ch += (char) 1; // 加1后,引起数据溢出,则ch为0/*int是有符号数,32位存储,表示范围是-2^31~2^31-1(即-2147483648~2147483647)*/
int i = Integer.MAX_VALUE; // i为2147483647
i += 1; // 加1后,引起数据溢出,则i为-2147483648

为什么要使用原码,反码,补码 ?

 

【加法器】计算机只有加法器没有减法器(计算机只能识别0和1,也就是高点平和低电平,最底层的运算就是0和1的各种数学运算,也就是二进制运算,又因为组成最基本的输入输出的逻辑门实现二进制加法最简单,所以所有的数学运算都是建立在加法基础上再通添加各种逻辑门来改进的),两个数的减法运算会被计算机转换为加法运算。目的:为了简化计算机基本运算电路,使加减法都只需要用过加法电路实现,也就是让减去一个整数或加上一个负数这样的运算可以用加上一个整数来代替。于是改变负数存储的形式,存储成一种可以直接当成正数来相加的形式,这种形式就是补码。

模数】模数从物理意义上讲是某种计量器的容量。经常举的一个例子就是钟表,其模数是12,即每到12就重新从0开始,数学上叫取模或者求余(mod)。java中用%表示求余,例如 14 % 12  = 2。如果此时的正确时间为6点,而你的手表指向的是8点,要把表对准,有两种方法:一是把表逆时针拨两小时;二是把表顺时针拨10小时。

即8-2=6,(8+10)%12 =6

也就是说在此模数系统里面有8-2=8+10

这是因为2跟10对模数12互为补数。因此有以下结论:在模数系统,A-B或A+(-B)等价于A+[B补],

即8-2或8+(-2)=8+10

我们把10叫做-2在模12下的补码。我们把补码表示法(two's complement representation)所表示的四位存储单

元,按照从0000到1111递增,均匀分布在时钟的表盘上。如下图所示:

顺时针方向为加法,逆时针方向为减法

模为2^n:在1111处顺时针拨一格,就到了0000。用数学的方式,即1111+1=10000,进位舍弃则结果为0000。那么四位存储的模就是10000(2^4),这样用补码来表示负数就可以将加减法统一成加法来运算,简化了运算的复杂的程度。

减法转换为加法:3-1=3+(-1)=0011+1111=0010,到这里有人就有疑问了,0011+1111明明等于10010,怎么会是0010呢?还记得之前提过的最高位进位舍弃嘛,因此对于4位存储来说,进位舍弃就是0010=2。

数据溢出:当0111(7)加1时,按照我们人的思维来说,应该结果为8,但是对于机器来说则不是,因为0111(7)是四位存储所能表示的最大符号数,所以它是无法表示01000(8)的,这个时候我们就说数据溢出了。机器的思考方式显然和我们人脑不一样,机器按照上面环形图的方式,由于0111(7)加1时顺时针造成的数据溢出,那么我们可以把机器的操作想象成在0111(7)处顺时针拨了一格,我们再去对照下环形图发现这个时候指向了1000(-8)。这个过程想象成拨时针就OK了,对于1000(-8)减1也是同样的道理。

 

至此,我们完全可以总结一下:

1、计算机只有加法器没有减法器,两个数的减法运算会被计算机转换为加法运算,而补码正好能够解决减法转换为加法的问题。

2、防止机器发生零重码,同时解决了原码和反码不能表示-8的问题,这样极大的简化了计算机的硬件设计。

3、以循环的方式解决数据溢出的问题

 

现在我们回归到正题:

1byte = 1字节 = 8bit ,1int = 4字节 = 32bit

比如-12,[0000 1100]原  ,[1111 0011]反  ,[1111 0100]补码

byte-->int,就是8位变成32位

系统检测到byte转int进行运算时,按符号位补位,高位全部补1:  1111 1111 1111 1111 1111 1111 1111 0100

0xFF的二进制表示:1111 1111 ,高位全部补0: 0000 0000 0000 0000 0000 0000 1111 1111

-12的补码与0xFF进行与(&)操作最后就是:  0000 0000 0000 0000 0000 0000 1111 0100(十进制是244)

 

当从数字类型扩展到较宽的类型时,补零扩展还是补符号位扩展。由于Java只有有符号数,当byte扩展到short, int时,即正数都一样,因为符号位是0,所以无论如何都是补零扩展,但负数补零扩展和按符号位扩展结果完全不同。

byte[] a = new byte[10];
a[0]= -127;
int c = a[0]&0xff;

补符号数,原数值不变。

原码:1111 1111    补码:1000 0001  转成int类型,高位补1: 1111 1111 1111 1111 1111 1111 1000 0001 这个32位二进制补码表示的也是-127,显然这个两个补码表示的十进制数字依然是相同。

补零时,相当于把有符号数看成无符号数。比如-127 = 0x81,看成无符号数就是129

原码:1111 1111  补码:1000 0001 转成int类型,高位补0 : 0000 0000 0000 0000 0000 0000 1000 0001 这个32位二进制补码表示的是129

也就是说,byte转int类型时,自动转型是按符号位扩展的,这样能保证十进制的数值不会变,而&0xFF是补0扩展,这样能保证二进制存储的一致性,但是十进制数值已经发生变化了。而正数可以说是既按符号位扩展,又是补0扩展,所以在二进制存储和十进制数值上都能保证一致。

 

参考:

https://www.jianshu.com/p/63cc96758d20

http://www.cnblogs.com/think-in-java/p/5527389.html

https://blog.csdn.net/xmc281141947/article/details/74740061

 

 

 

这篇关于Java中byte转int类型为什么要amp;amp;amp;amp;amp;0xFF?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/645463

相关文章

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll