Java的byte类型详解

2023-11-07

前言

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));
//结果
11111111 11111111 11111111 10000000

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

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

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

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

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

要注意-128是不能用常规的方式转换成补码的,只是规定了10000000这个值用来表示-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 10001100

强转后结果为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,转换成二进制就是11001000。在Java中计算时,因为byte会转换成int类型,所以计算的结果200用二进制表示就是

00000000 00000000 00000000 11001000

强转成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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java的byte类型详解 的相关文章

  • 方法返回类型前的 是什么意思?

    下面的方法返回一个List组成T类型元素 public
  • 枚举的子类化

    有没有一种简单的方法来子类化Javaenum 我问这个问题是因为我有大约 10 个实现相同接口的对象 但它们对某些方法也有相同的实现 因此我想通过将所有相同的实现放置在扩展的中间对象中来重用代码Enum它也是我需要的所有其他类的超类 或许事
  • “源兼容性”和“目标兼容性”有什么区别?

    之间有什么关系 区别sourceCompatibility and targetCompatibility 当它们设置为不同的值时会发生什么 根据工具链和兼容性 https docs gradle org current userguide
  • java程序有多少种结束方式?

    我知道使用 System exit 0 可以结束一个java程序 例如 如果我有一个JFrame窗口 它会关闭并结束程序 但我想知道还有多少其他方法 可以关闭它并结束程序 包括发生错误时 程序会被关闭 JFrame也会被关闭吗 添加到其他答
  • 如何在 Android 应用程序中隐藏 Flutterwave API 密钥

    我正在构建一个 Android 应用程序 目前正在将 Flutterwave 集成到我的应用程序中以进行支付 建议我永远不要将 Flutterwave API 密钥放在我的应用程序上 那么我该如何隐藏这些键呢 我正在使用 Retrofit
  • 查看Java Agent修改的Java类的源代码

    我需要了解 Java 代理如何修改我的初始类 以便我能够理解代码的作用 build gradle configurations jar archiveName agent2 jar jar manifest attributes Prema
  • 无法使用 datastax java 驱动程序通过 UDT 密钥从 cassandra 检索

    我正在尝试使用用户定义的类型作为分区键将对象存储在 cassandra 中 我正在使用 datastax java 驱动程序进行对象映射 虽然我能够插入到数据库中 但无法检索该对象 如果我更改分区键以使用非 udt 例如文本 我就能够保存和
  • Java中Gson、JsonElement、String比较

    好吧 我想知道这可能非常简单和愚蠢 但在与这种情况作斗争一段时间后 我不知道发生了什么 我正在使用 Gson 来处理一些 JSON 元素 在我的代码中的某个位置 我将 JsonObject 的 JsonElements 之一作为字符串获取
  • JOOQ 忽略具有默认值的数据库列

    看来JOOQ完全忽略了数据库列的默认值 既不会更新 ActiveRecord 对象 也不会在 INSERT 时跳过此列 相反 它尝试将其设置为 NULL 这在 NOT NULL 列上失败 Example CREATE TABLE bug f
  • JAXB - 忽略元素

    有什么方法可以忽略 Jaxb 解析中的元素吗 我有一个很大的 XML 文件 如果我可以忽略其中一个大而复杂的元素 那么它的解析速度可能会快很多 如果它根本无法验证元素内容并解析文档的其余部分 即使该元素不正确 那就更好了 例如 这应该只生成
  • Android 认为我没有关闭数据库!为什么?

    我有一个 SQLiteDatabase 数据成员 我在 onCreate 中初始化它 并在 onPause onStop 和 onDestroy 中调用 close 它在 onResume 中重新初始化 它似乎运行得很好 但当我查看调试器时
  • 无需递归即可对可观察结果进行分页 - RxJava

    我有一个非常标准的 API 分页问题 您可以通过一些简单的递归来处理 这是一个捏造的例子 public Observable
  • 在java程序中使用c++ Dll

    我正在尝试使用System LoadLibrary 使用我用 C 编写的一个简单的 dll UseDllInJava java import com sun jna Library import com sun jna Native imp
  • 数据库中的持久日期不等于检索日期

    我有一个具有 Date 属性的简单实体类 此属性对应于 MySQL 日期时间列 Entity public class Entity Column name start date Temporal TemporalType TIMESTAM
  • 如何向页面添加 HTML 页眉和页脚?

    如何使用 itext 从 html 源添加标题到 pdf 目前 我们已经扩展了 PdfPageEventHelper 并重写了这些方法 工作正常 但当我到达 2 个以上页面时 它会抛出 RuntimeWorkerException Over
  • Azure Java SDK:ServiceException:ForbiddenError:

    尝试了基本位置检索器代码 如下所示 String uri https management core windows net String subscriptionId XXXXXXXX 5fad XXXXXX 9dfa XXXXXX St
  • Android计算两个日期之间的天数

    我编写了以下代码来查找两个日期之间的天数 startDateValue new Date startDate endDateValue new Date endDate long diff endDateValue getTime star
  • 用于请求带有临时缓存的远程 Observable 的 RxJava 模式

    用例是这样的 我想暂时缓存最新发出的昂贵的Observable响应 但在它过期后 返回到昂贵的源Observable并再次缓存它 等等 一个非常基本的网络缓存场景 但我真的很难让它工作 private Observable
  • 如何让 Firebase 与 Java 后端配合使用

    首先 如果这个问题过于抽象或不适合本网站 我想表示歉意 我真的不知道还能去哪里问 目前我已经在 iOS 和 Android 上开发了应用程序 他们将所有状态保存在 Firebase 中 因此所有内容都会立即保存到 Firebase 实时数据
  • Java 的“&&”与“&”运算符

    我使用的示例来自 Java Herbert Schildt 的完整参考文献 第 12 版 Java 是 14 他给出了以下 2 个示例 如果阻止 第一个是好的 第二个是错误的 因此发表评论 public class PatternMatch

随机推荐

  • 【毕业设计】深度学习行人重识别系统 - person reid

    文章目录 0 前言 1 技术背景 2 技术介绍 3 重识别技术实现 3 1 数据集 3 2 Person REID 3 2 1 算法原理 3 2 2 算法流程图 4 实现效果 5 部分代码 6 最后 0 前言 Hi 大家好 这里是丹成学长的
  • css强制换行和禁止换行

    强制换行 word break break all 只对英文起作用 以字母作为换行依据 word wrap break word 只对英文起作用 以单词作为换行依据 white space pre wrap 只对中文起作用 强制换行 禁止换
  • SpringBoot注解+AOP实现

    SpringBoot注解 AOP实现 Java Annotation注解的详解 Java注解是一种元数据 它可以用于在类 方法或其他代码结构中声明关于程序元素的信息和标记 在Java中 注解以 符号开头 在编译时或运行时由Java虚拟机 J
  • TEA、XTEA、XXTEA加密解密算法

    参考 TEA XTEA XXTEA加密解密算法 地址 https blog csdn net gsls200808 article details 48243019 其他相关博文链接 tea系列加密算法学习笔记 TEA和XxTEA跨平台加密
  • 【其他】资源整合

    偶然整理云盘 发现曾经收藏过一些比较不错的资源 正好分享一下 1 C语言教程 郝斌老师作为读书时候的启蒙老师 推荐一波 链接 https pan baidu com s 10NIZ3x4yPP4YP8bYmVENHg 密码 6jj1 2 U
  • Node的Buffer对象和fs模块

    一 Node的模块化管理 1 模块化 node应用程序由模块组成 遵循的是CommonJS模块规范 使用模块管理的好处是隔离模块的作用域 避免出现命名冲突 2 什么是CommonJS 是一套代码的规范 构建一个在浏览器之外的JavaScri
  • C/C++编程:仿函数

    概述 仿函数 也叫做函数对象 就实现意义而言 函数对象 比较贴切 一种具有函数特性的对象 就行为而言 仿函数 更贴切 这种东西可以像函数一样被调用 被调用者则以对象所定义的function call operator扮演函数的实质角色 仿函
  • &2 应用层 - 应用层协议原理

    应用层协议原理 一 网络应用程序体系结构 客户机 服务器 体系结构 纯P2P 体系结构 客户机 服务器与P2P的混合 二 进程通信 客户机和服务器进程 套接字 socket 进程与套接字关系 进程寻址 进程识别信息 两部分 用户代理 use
  • C++中的vector容器 模板类有两个参数

    std vector lt Eigen Matrix3d Eigen aligned allocatorEigen Matrix3d gt vector的声明如下 template
  • 记录用户上次看视频的进度,并且从记录的时间继续观看

    思路 因为视频多个 所以定义一个数组接收该用户已观看但是未观看完毕的字段 videoPlanArr 第一次进入获取本地储存的字段 videoPlanArr 如果没有获取到的话储存该视频id 有的话查询是否在数组中 未找到就把视频id添加进v
  • 数据库分库分表实战

    一 使用场景 当单个数据库实例达到瓶颈 例如连接数过多 处理能力受限 存储容量不足 磁盘IO达到瓶颈 内存不足 都需要对数据库进行分库分表 二 垂直切分 数据库表按列拆分 拆分后 数据库从一个数据列多的表变成了多个数据列少的表 数据垂直切分
  • win10系统 总是显示执行此操作需要Internet

    最近在重新设置电脑登录方式时 系统总是显示 执行此操作需要Internet 解决方法如下 首先右键开始图标 以管理员身份打开PowerShell 然后输入 netsh winsock reset 进行重置 winsock是Windows网络
  • 关于对数据结构的理解

    数据结构是计算机存储 组织数据的方式 数据结构是指相互之间存在一种或多种特定关系的数据元素的集合 数据结构反映数据的内部构成 即数据由那部分构成 以什么方式构成 以及数据元素之间呈现的结构 数据结构就是研究数据的逻辑结构和物理结构以及它们之
  • 数据库总结(七)

    数据库设计 7 1 数据库设计概述 1 数据库设计 数据库设计是指对于一个给定的应用环境 构造 设计 优化的数据库逻辑模式和物理结构 并据此建立数据库及其应用系统 使之能够有效地存储和管理数据 满足各种用户的应用需求 包括信息管理要求和数据
  • Spring AOP 剖析(6)

    Spring AOP 的底层实现机制 2 Spring AOP 中的 Pointcut 6 扩展 Pointcut 如何前面的 Pointcut 类型都无法满足要求 这种情况下可以扩展 Spring AOP 的 Pointcut 给出自定义
  • web复习之从头到尾看看(1)

    主要是一些我认为自己没有掌握的细节性问题 仅供参考 欢迎大家一起学习 留言 你认为最有可能考的内容 换行标签 lt gt 内加br br span 不能包含 div 与 p 超链接 a href 链接内容 target 在何处打开 self
  • Python绘制三角函数图像

    可以使用Python的matplotlib库来绘制三角函数图像 首先 定义一个x值的范围 然后使用matplotlib的plot 函数绘制三角函数 最后使用matplotlib的show 函数显示图像
  • HTML 取消input自动提示

    input 输入框有提示功能 当你之前输入过一些内容 你下次打入相关字符的时候 默认会有之前输入的一些相关的字符的提示 这个提示一般来说还是很好的 但是 有时候 我们想自己输入 不想要提示 如果不需要提示 则将 autocomplete设置
  • ubuntu的终端命令提示符太长的修改方法总结

    2019独角兽企业重金招聘Python工程师标准 gt gt gt ubuntu的终端命令提示符太长 主要原因 1 计算机名太长 2 多层直接显示出来 针对计算机名太长的处理 如 下面的计算机名提示太长了 ningcaichen virtu
  • Java的byte类型详解

    前言 byte这个单词是Java八种基本数据类型之一字节的关键字 在计算机存储中以字节为单位 8位比特 bit 组成一个字节 为什么弄清楚byte这么重要呢 因为智能硬件的数据传输大部分协议都是按字节一位一位来解析的 对于字节的运算十分频繁