Java的byte类型详解

Java的byte类型详解byte 是 java 的基本数据类型之一 在计算机存储中以字节为单位 8 位比特 bit 组成一个字节 为什么弄清楚 byte 这么重要呢 因为智能硬件的数据传输大部分协议都是按字节一位一位来解析的 对于字节的运算十分频繁 如果不对 byte 研究透彻 就很容易犯一些特别基础的错误

前言

byte这个单词是Java八种基本数据类型之一字节的关键字,在计算机存储中以字节为单位,8位比特(bit)组成一个字节。
为什么弄清楚byte这么重要呢?因为智能硬件的数据传输大部分协议都是按字节一位一位来解析的,对于字节的运算十分频繁,如果不对byte研究透彻,就很容易犯一些特别基础的错误。

1.取值范围

byte由8位bit组成,每个bit只能是0或者1,所以byte一共有2的8次方种可能,也就是256。

这样来说byte的取值范围就应该是0~256了吧,但是在Java中有一点需要特别注意,除了boolean和char是无符号的,其余的基本数据类型都是有符号的。而符号要怎么表示的,答案就是用最高位来标识,0为正数,1为负数。

若byte为正数,则其最大值为

0111 1111 //转换为10进制,2^6+2^5+2^4+2^3+2^2+2^1+1=127 

若byte为负数,则其最大值为

1111 1111 //-127 

故byte的取值范围是-127~127。

但这个结论与我们在各种Java教程中看到的取值范围不吻合,byte的真正取值范围是

-2^8~2^8-1 即是 -128~127 

这个多出来的-128是怎么用字节表示的呢,用下面代码打印出-128的二进制表示。

byte b1 = -128; System.out.println(Integer.toBinaryString(b1)); //结果     

截取最后8位,所以-128的二进制表示为,从表面上看就是-0。

实际上我们将二进制1111 1111表示的数字打印出来也不是-127,而是-1,可用下面代码进行验证

 byte b1 = (byte) 0B; System.out.println(b1); //结果 -1 

出现这种情形是因为计算机用补码的方式存储数值,关于补码详细介绍可参考这篇文章。

简而言之就是,正数的补码是自身,而负数的补码则是其绝对值按位取反再加1

要注意-128是不能用常规的方式转换成补码的,只是规定了这个值用来表示-128。

2.为何赋值时会经常报错?

在编码过程中,经常会遇到给byte变量赋值时报错,提示的错误如下

byte b1 = 0x8F; //报错提示 Incompatible types Required:byte Found:int 

意思就是类型不兼容,需要的是byte型,但给的是int型。int型的数值范围比byte大,会导致大于127的值无法正常表示,所以会报错。解决报错的方法就是将等号右边的字面值强转为byte。

byte b1 = (byte) 0x8F; //-113 

在Java中,所有整型字面值都是int型,所有小数都是double型

在上述的错误中0x8F被当成int型,并且其未带负号,转换成10进制为143。而byte的取值范围是-128~127,明显小于143,数值超出了byte的最大值,所以编辑器会报错,只能用强转的方式将int的最后8位截取掉变成byte类型。

对byte的赋值几乎都是采用16进制表示的,如上述的0x8F,在很多情况下byte类型的变量并不是想看其十进制的值,而是想知道每一个bit的值,用二进制表示显得过长,而用16进制表示一个byte只需要两位即可,每一位表示4个bit。

什么情况下byte的赋值会报错提示类型不对呢?那就是当数值大于127,换句话说就是byte的最高位为1时,在16进制里面就是当第1位大于7时就会报错。

byte b1 = 0x7F; //不报错,无须强转 byte b2 = 0x80; //报错,必须要强转 

3.基本四则运算注意点

首先来看一个byte运算的例子

byte b1 = 0x20; byte b2 = 0x10; byte b3 = b1 - b2; //报错 //正确 byte b3 = byte(b1-b2); 

我们会发现最后一句代码报错,提示也是类型不兼容,需要的是byte,而给的int。从表面上看b1-b2的值为16,绝对没有超过127,为何也会报错呢?

原因就在于Java的运算机制,在Java中两个变量只要参与了数学运算,就有可能会进行类型提升,只要类型比int小(即byte,char,short),那么在运算之前,这些值会自动转换成int。

通常表达式中出现的最大的数据类型决定了表达式最终结果的数据类型。如果将一个float值与一个double值相乘,结果就是double,如果将一个int和一个long值相加,则结果为long。

用byte运算要注意,如果结果的类型也是byte,有可能会发生负数运算后成正数,正数运算后变成负数的情况。看下面的例子:

byte b4 = (byte) 0xA1; byte b5 = (byte) (b4*2); System.out.println("b4="+b4+",b5="+b5); //结果 b4=-95,b5=66 byte b6 = 0x46;//十进制为70 b6*=2; //预期结果应为140 System.out.println("b6="+b6); //结果 b6=-116 

b4值为-95,乘以2得到-190,因为运算时会转换成int类型,-190的二进制为

1111 1111 1111 1111 1111 1111 0100 0010 

再对-190进行强转,截取最后8位变成byte,最后结果的二进制为

0100 0010 //66 

b6的值为0x46,转换成十进制为70,乘以2结果为140,二进制表示为

00000000 00000000 00000000  

强转后结果为1000 1100,由于最高位是1,则说明值已经是个负数了。可怎么看起来这个值不像是-116的,而应该像-12的。这就涉及到补码了,这个二进制只是在计算机中的存储表示,要经过转换方能得到真值。转换过程如下:

  • 最高符号位不变,其余位全部取反,得到1111 0011
  • 再加1,得到1111 0100
  • 符号位不计算,其余7位转换为10进制的值是 64+32+16+4=116
  • 再加上负号,最终结果为-116。

最后结论是用byte运算并且结果也是byte时要注意结果的符号可能会翻转,当计算的值大于127或者是小于-127时符号就会翻转,翻转后的值与真正的值两者的绝对值之和必定是256。

4.位操作运算

Java中的位操作有4种,分别是与&,或|,非~,异或^,位操作就是指对每一个bit进行操作,操作时将数据用二进制表示会更加直观,下面是位操作的运算规则说明。

操作符 值1 值2 结果
& 0 1 0
| 0 1 1
~ NA 1 0
^ 0 1 1

byte类型在位操作运算时都会转成int类型,运算的结果也是int类型。

在许多通信协议中会看到最后一位字节是校验位,校验值也分为很多算法,常见的有求和与异或校验,假如求和的值超过了byte的最大值,这种情况下会造成校验不准吗?

答案是不会,假设在C中计算的校验和是unsigned char类型,累加校验值假定为200,转换成二进制就是。在Java中计算时,因为byte会转换成int类型,所以计算的结果200用二进制表示就是

00000000 00000000 00000000  

强转成byte为1100 1000,十进制为-56,虽然看起来和C中的值符号不一致,但在二进制中两者的每一位都是相同的,实际上两者在Java中就是相等的,所以累加和之类的校验可以计算出前几位的和并强转成byte之后直接与最后一位的校验值比较是否相等。

虽然校验值可以不用转换直接对比,但是其他的数据字节计算就需要转换了。最常见的就是单片机用串口发送不了浮点数据过来,只能发一个字节的整型,所以普遍的做法就是发两个字节代表浮点数,高位与低位,计算公式为

(高位字节*256 + 低位)/100 

很明显这个高低位字节在C中就是无符号char,是不会出现负数的。

假如需要发送599.21的浮点值,那么高位值就为0xEA,低位值为0x11,在Java中用这个公式计算得到的结果却是一个负数。

b1 = (byte) 0xEA; b2 = 0x11; float f1 =( b1 * 256 + b2)/100F; System.out.println("f1="+f1); //结果 f1=-56.15 

在这种情况下,高位和低位的字节都必须先转换成正数再去进行计算。Java中的byte转换成正数的方式如下。

b1 = (byte) 0xEA; System.out.println("b1="+b1); int i1 = b1 & 0xFF; System.out.println("i1="+i1); //结果 b1=-22 i1=234 

切忌使用b1&=0xFF这种方式进行转换,byte想要转换成正数必须要提升类型,所以这里使用了int类型来保存与0xFF位与运算后的结果。

用这种转换方法再来计算一遍上述的浮点值,就能得到正确的结果

b1 = (byte) 0xEA; b2 = 0x11; float f1 =( (b1&0xFF) * 256 + (b2&0xFF))/100F; System.out.println("f1="+f1); //结果 f1=599.21 

在串口通信中,还有另外一种操作是经常使用的,那就是取某几个bit的值,这就需要用到移位操作了。

假如有一个字节为0x9A,需要取最高两位的值,取值方法如下:

//0B1001 0110 最高位为10,值应为2 b1 = (byte) 0x96; b1 = (byte) ((b1 & 0xFF)>>6); System.out.println("b1="+b1); //结果 b1=2 

在移位之前一定要跟0xFF相与转成正数,避免在移位时有1的值移到前8位里面造成结果错误。

注:称位操作在Java中有3种,

  • 左移<<,低位补零
  • 右移>>,若符号为正则在高位插入0,符号为负则在高位插入1
  • 无符号右移>>>,无论正负,都在高位插入0
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/199138.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午1:46
下一篇 2026年3月26日 下午1:46


相关推荐

  • ORA-01017解决方案「建议收藏」

    ORA-01017解决方案「建议收藏」ora-01017是用户登录的报错。解决思路:1)确认所登用户的状态。可能是被锁了,可能是密码过期状态。修改之,即可2)当然是确认用户名密码是否输入正确。不确定密码的话可以重设。3)oracle-12C有了数据库容器概念。所登用户是否在PDBORCL里,tnsnames.ora文件里是否配置了PDBORCL,登录时是否选中了PDBORCL4)所登用户是否是sysdba。是的话登录语句要加assysdba这4步确定好了,能解决100%的ora-01017报错情况。…

    2022年5月31日
    81
  • Agent AI插件

    Agent AI插件

    2026年3月15日
    7
  • 在PyCharm下使用Jupyter Notebook[通俗易懂]

    在PyCharm下使用Jupyter Notebook[通俗易懂]在PyCharm中新建JupyterNotebook文件步骤:File->New…->JupyterNotebook->输入文件名建好之后效果如下图所示,熟悉的JupyterNotebook输入代码,点击绿色三角图标,运行,出现窗口如下:点击“Cancel”取消,点击左下角的“Terminal”,输入“Jupyter-notebook”…

    2022年8月25日
    58
  • mysql数据库优化总结

    mysql数据库优化总结

    2021年10月15日
    42
  • @Page指令中的AutoEventWireup

    @Page指令中的AutoEventWireup以前根本不注意AutoEventWireup这个小小的属性,但是后来由于它产生的许多麻烦使我不得不研究它,并最终领悟了它。如果你写了一个asp.net页面,里面包含了服务端脚本:voidPage_Load(objectsender,EventArgse){lblMessage.Text=”ThinkinginTechmango.com”;}

    2022年5月28日
    40
  • 爆笑三国之张飞流水账【爆笑中体验哲理】「建议收藏」

    爆笑三国之张飞流水账【爆笑中体验哲理】「建议收藏」
    张飞流水帐一
    我写这个流水帐的时候,大哥和二哥都在睡觉,军师也在睡觉。
    赤兔马站在我窗外,也在睡觉。
      小时侯我就研究马为什么会站着睡觉,研究了很长一段时间后,我发现没有答案。而苦恼的是我的童年唯一能记起的事就是这个了。

      长大以后有段时间我开始研究大哥和二哥为什么要睡在一张床上,同样也没有答案。
      这个世界有太多的事是没有答案的,军师对我说过。
      在我睁大眼睛思考问题的时候,我养成了睁眼睡觉的习惯,不

    2022年7月16日
    20

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号