JAVA基本数据类型与byte互相转换(位运算,原码,补码)

2023-11-06

最近整理了之前的一些知识,做了一个java中byte类型与int ,long转换以及将字节信息表示成字符串形式的工具。对前面的只是做了一下复习整理。

原码、反码、补码:

首先这三者都是二进制码即(0,1组合)。

原码:最高位为符号位,0表示正数,1表示负数,剩余部分表示真值。

反码:正数的反码是他本身,负数的反码是在原码基础上符号位不变,其余部分按位取反

补码:反码基础上末位加1。

举个例子(以数值-8的单字节表示为例):

原码:1000 1000(红色为符号位,其余所有位组成数值)

反码:1111 0111

补码:1111 1000

注意:计算机中保存的数据都是以补码形式存在或计算的。原码是方便你计算的,纸上算数用的东西。 

位运算:

顾名思义,位运算就是用来操作比特位的。需要用到的几个位运算符:

&按位与(全真为真,一假则假)(1为真,0为假)

|按位或(一真为真,全假则假)

>> 带符号左移  >>> 无符号左移

<<右移

java中强制类型转换到底做了什么?

首先你得知道java中对于小于四字节的基本数据类型(short,char,boolean,byte,float)内部进行运算时全部转为四字节。当然int和float本身就是四字节的。long和double都是八字节。

通过一个测试类来分析一下这个问题:

public class Test1 {

	public static void main(String[] args) {
		//-256:原码:10000000 00000000 00000001 00000000  --->补码:11111111 11111111 11111110 00000000
		//低8位为:00000000		结果0
		int num = -256;
		byte bNum = (byte) num;
		System.out.println(bNum);   
		

		//-4:原码10000000 00000000 00000000 00000100 --->补码:11111111 11111111 11111111 11111100
		//低8位:11111100(补码) ----->原码:10000100   结果-4
		num = -4;
		bNum = (byte)num;
		System.out.println(bNum);
		
		//5201314:原码==补码(正数):00000000 01001111 01011101 10100010		
		//低8位为:10100010(补码) ---> 原码:11011110  == -94
		num = 5201314;
		bNum = (byte) num;
		System.out.println(bNum);		
	}
}

 

三个输出:与注释中的分析一样int类型强转为byte时可以确定他就是直接砍掉前面24位的。long型也一样。它将自己保存的补码信息拿出来,只保留最后八位。

对一个运算过程的分析思考:

计算机底层的运算都是针对补码的运算(得在强调一遍)

在下面的例子中我定义了一个byte类型的变量b,简单测试分析了一下  b >>> 4的过程(其实也是为了加深我对原码补码的理解,之前只是记得知识确实感觉自己有些晕)。分析写在注释中:

public class Test2 {

	public static void main(String[] args) throws Exception {
		byte b = (byte) 0xCA;		//-54   --- 原码 1011 0110---补码 1100 1010

		System.out.println("------------------测试(byte)(b >>> 4)的整个过程-----------------------------");
		//java中基本数据类型在进行运算时 变量b操作数小于四字节,好的转为int型:
		//b扩充为4字节后(注意高位补的是符号位 b的补码的符号位现在是1  !!!) :  
		//11111111 11111111 11111111 11001010(补码)
		//无符号右移(高位全部补0)4位之后,符号位变为0(正数的原码补码相同)
		//00001111 11111111 11111111 11111100(补码)      不出问题的话结果应该是:268435452
		System.out.println((b >>> 4));		//输出:268435452
		
		//int类型又转换为byte类型了:直接砍掉前面24位结果如下:
		//11111100(补码)  好的我们现在要在纸上算出来值是多少了,来先将其转换为原码10000100  结果为-4
		System.out.println((byte)(b >>> 4));		//输出为-4
		
		//如果此时在给(byte)(b >>> 4)的结果来个  &0x0F  
		//java:好的先将byte转为int型(补符号位)----->结果:11111111 11111111 11111111 11111111 11111100
		//0x0F: 00000000 00000000 00000000 00001111
		//两个按位与的结果为:00000000 00000000 00000000 00001100----结果: 12
		System.out.println((byte)(b >>> 4) & 0x0F);		//输出12
	}

}

显然跟分析的一样,所以那一套确实得到了验证。

编写工具类:

功能一:实现将字节信息以字符串形式显示出来(16进制表示):

public class MecBinary {
	private static final String HEX = "0123456789ABCDE";
	
	/**
	 *  将字节数组中的字节转换成字符串形式表示的16进制信息
	 * @param bytes		字节数组
	 * @param len		要处理的长度
	 * @param offset	字节数组的起始处理位置
	 * @return
	 */
	public static String binaryToHexString(byte[] bytes, int len, int offset) {
		StringBuffer res = new StringBuffer();
		
		for(int index = offset; index < len + offset; index++) {
			//取出一个字节
			byte b = bytes[index];			//假如取出来的字节为 0xCA ----二进制为 1100(C) 1010(A)
			/*
			 * 现在的目的是将这个字节转换为字符串形式的CA (HEX中下标为12 与 10的字符组合)
			 * >>表示带符号右移		>>>表示无符号右移,高位补0
			 * 当 b >> 4 ---> 1111 1100   
			 */
			res.append(HEX.charAt(b >> 4) & 0x0F);		//取出高四位对应的16进制字符
			res.append(HEX.charAt(b & 0x0F));			//取出低四位对应的16进制字符
		}
		return res.toString();
	}
	
	/**
	 *  将字符串表示的16进制信息转换成字节
	 * @param str
	 * @return
	 */
	public static byte[] hexStringToBinary(String str) {
		if(str == null || str.isEmpty()) {
			return null;
		}
		int len = str.length();
		/*
		 * 首先需要明确的是字符串中的字符个数不能是奇数个, 因为一个字节8个比特位 ,16进制数可用4位表示
		 * 也就是说两个字符代表一个字节
		 */
		if(len % 2 != 0) {
			return null;
		}
		byte[] result = new byte[len / 2];
		
		for(int index = 0; index < len; index += 2) {
			/*
			 * 以CA为例	: 
			 * 取出字符C对应的下标---12 00000000 00000000 00000000 00001100(原码==补码)
			 * 取出字符A对应的下标---10 00000000 00000000 00000000 00001010(原码==补码)
			 * 现在的目的是得到 单字节:1100 1010
			 * 将12左移4位 与 10进行&运算 ===>  (12 << 4) & 10
			 * 即二进制形式变为:00000000 00000000 00000000 11001010   然后转换为单字节去掉其前面24位。即只保留 1100 1010
			 */
			int hVal = HEX.indexOf(str.charAt(index));
			int lVal = HEX.indexOf(str.charAt(index + 1));
			
			//index 只可能是 0 2 4 6 8...   我们要的是:0,1,2,3,4...    index >> 1  表示 / 2
			result[index >> 1] = (byte) ((hVal << 4) | lVal);
		}
		
		return result;
	}
	
}

 测试类:读取一个mp3文件中的部分字节在写入到另一个文件中,看看是否一样。

public class Test3 {

	public static void main(String[] args) throws Exception {
		FileInputStream fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\leftHand.mp3");
		byte[] buffer = new byte[16];
		fis.read(buffer);
		String hexStr = MecBinary.binaryToHexString(buffer, 16, 0);
		System.out.println(hexStr);
		
		//将转换过来的字符串转换成字节存储进字符数组中。并写入文件
		FileOutputStream fos = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\test.mp3");
		buffer = MecBinary.hexStringToBinary(hexStr);
		fos.write(buffer);
		
		fis.close();
		fos.close();
		
	}

}

 

显示结果:

功能二:实现int类型与byte数组中字节之间的互转:

	/*
	 *  将int类型的数据转换成字节存储进字节数组中    int类型占4个字节
	 */
	public static byte[] intToBytes(int val) {
		byte[] result = new byte[4];
		/*
		 * 	比如现在val如下:高-->低
		 * 	   字节1	       字节2          字节3            字节4
		 * 	00000011 00110000 00110000 11001010
		 */
		for(int index = 0; index < 4; index++) {
			/*
			 * index << 3 四次取值分别为 0,8,16,24  即相当于遍历每个字节了
			 * 	强转为byte类型时他会直接砍掉前面24位。
			 * 	这个是由低位到高位处理的,即存储的顺序是 [字节4,字节3,字节2,字节1] 
			 */
			result[index] = (byte) (val >> (index << 3)); 
		}
		return result;
	}
	
	/**
	 * 	将int类型数据转换成字节数组并加到buffer的指定位置处
	 * @param buffer
	 * @param offset
	 * @param intValue
	 * @return
	 */
	public static byte[] intToBytes(byte[] buffer, int offset, int val) {
		byte[] bytes = intToBytes(val);	
		
		for(int index = 0; index < 4; index++) {
			buffer[offset + index] = bytes[index];
		}
		return buffer;
	}
	
	public static int bytesToInt(byte[] buffer, int offset) {
		int result = 0;
		for(int index = 3; index >= 0; index--) {
			/*
			 * 由高位到低位处理  这里一定要加0xFF  此处暂且记为  标号1处。后面将说明为什么必须加
			 */
			result <<= 8;
			result |= buffer[index + offset] & 0xFF;
		}
		return result;
	}
	
	public static int bytesToInt(byte[] bytes) {
		return bytesToInt(bytes, 0);
	}

对于上述bytesToInt(byte[] buffer, int offset)方法中即标记1处为什么一定要加0xFF解释,在不加的情况下测试一下:

public class TestBinary {

	public static void main(String[] args) {
		System.out.println(MecBinary.bytesToInt(MecBinary.intToBytes(128)));
        }

}

输出结果为-128(反转换出的结果是错的。。。)分析:

128的原码:00000000 00000000 00000000 10000000(正数补码相同)
128通过intToBytes转换之后数组内部情况[10000000,00000000,00000000,00000000]
 然后通过bytesToInt转化过程:
 前三此转换都没出错 经过三次转换后result的结果为 00000000 00000000 00000000 00000000
 最后一次发生了什么?
 result << 8的结果:00000000 00000000 00000000 00000000
 result = result | bytes[0]  出问题了:
 bytes[0]--->10000000  java先将其转化为int型(补符号位!!!)结果为:
 11111111 11111111 11111111 10000000 result与此值进行按位或运算结果为:
 11111111 11111111 11111111 10000000(补码)这是个负数。来我们算一下它的值,将其转为原码如下:
 10000000 00000000 00000000 10000000 -----这是  -128
 所以我们要加上  &0xFF  这样可以才可以保证不出错。

功能三:实现long类型与byte数组中字节之间的互转:这个就跟上面操作int的道理一样了没什么可分析的,贴上代码:

	public static byte[] longToBytes(long val) {
		byte[] result = new byte[8];
		for(int index = 0; index < 8; index++) {
			result[index] = (byte) (val >> (index << 3)); 
		}
		return result;
	}
	
	public static byte[] longToBytes(byte[] buffer, int offset, long val) {
		byte[] bytes = longToBytes(val);
		
		for(int index = 0; index < 8; index++) {
			buffer[offset + index] = bytes[index];
		}
		
		return buffer;
	}
	
	public static long bytesToLong(byte[] buffer, int offset) {
		long result = 0;
		
		for(int index = 7; index >= 0; index--) {
			result <<= 8;
			result |= buffer[index + offset] & 0xFF;
		}
		
		return result;
	}
	
	public static long bytesToLong(byte[] bytes) {
		return bytesToLong(bytes, 0);
	}

最后来综合测试一下功能一功能二:

public class TestBinary {

	public static void main(String[] args) {
		//测试将两个int类型数据一个long类型数据存入字节数组中并反解析出来
		byte[] buffer = new byte[16];
		
		MecBinary.intToBytes(buffer, 0, 87);
		MecBinary.intToBytes(buffer, 4, -99);
		MecBinary.longToBytes(buffer, 8, 5201314L);
		
		System.out.println(MecBinary.bytesToInt(buffer, 0));
		System.out.println(MecBinary.bytesToInt(buffer, 4));
		System.out.println(MecBinary.bytesToLong(buffer, 8));
	}

}

输出结果:

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

JAVA基本数据类型与byte互相转换(位运算,原码,补码) 的相关文章

  • Java接口以及static和final关键字

    Java接口以及static和final关键字 一 static 二 final 三 让final元素可以初始化 不用固定赋值 四 接口 五 抽象方法 六 接口能够创建对象吗 匿名内部类 七 另一实例 开锁 一 static static代
  • Swagger3 注解使用(Open API 3.0)

    文章目录 前言 一 swagger 3 的使用 Swagger SpringFox 3 0 相关特性 SpringDoc 二 从 spring fox 迁移到 springdoc 三 使用 swagger3 注解代替 swagger2 的
  • 【一】第一个java程序详解

    第一个java程序详解 一 前言 二 创建并编写java源代码的文件 创建java源代码文件 更改文件后缀 java代码的结构 三 编译执行 编译 执行 四 总结 五 附 java关键字 一 前言 通过之前上一节 开篇 Java语言介绍及环
  • 使用jemeter进行压力测试关注的指标

    一 压测设置 线程数 并发数量 能跑多少量 具体说是一次存在多少用户同时访问 Rame Up Period in seconds 表示JMeter每隔多少秒发动并发 理解成准备时长 设置虚拟用户数需要多长时间全部启动 如果线程数是20 准备
  • 接口如何实现多态

    抽象类是用来继承的 不能被实例化 抽象类里可以有成员变量 接口中没有 1 抽象类里的抽象方法 只有在子类实现了才能使用 2 抽象类里的普通方法 可被子类调用 3 接口里的方法 都被默认修饰为public abstract类型 4 接口里的变
  • FullGC问题分析

    一 常见的FullGC场景分析 频繁的大对象 大对象直接被分配到老年代 系统高负载运行 请求量很大 jvm来不及将对象转移到老年代 直接到老年代分配对象 系统内存泄漏 导致对象长时间在老年代 得不到释放 二 产生FullGC的原因 Syst
  • MVC发展历程及思想

    两种web应用程序的开发模式 model 1 JSP JavaBean JSP负责 页面显示 页面跳转 调用Javabean处理数据 处理请求 JavaBean负责 数据封装保存 数据处理逻辑 适用场景 model 1 方式适合开发业务逻辑
  • Java Json 数据下划线与驼峰格式进行相互转换

    概述 今天遇见一个需求 需要对json数据进行下划线与驼峰格式之间进行转换 在Fastjson Jackson Gson都提供了转换的方式 在这里进行一下列举 User类 public class User private String n
  • Java中变量的作用域【Java基础】

    最近在看 Thinking in Java 想把Java基础再巩固一下 在博客上遇到的以前没注意到的知识点或者较难的知识点记录下来 与大家分享 Java中的基本类型变量的作用域为 int x 1 变量x的作用域只在大括号内 System o
  • 各种注释总结

    jsp注释 html注释
  • [透彻]为什么要前后端分离?

    前后端分离的意义 前后端分离 已成为互联网项目开发的业界标准使用方式 前后端分离 会为以后的大型分布式架构 弹性计算架构 微服务架构打下坚实的基础 核心思想 前端页面调用后端的restuful api接口 并使用json数据进行交互 服务器
  • ubuntu 11配置hadoop

    最近没事 研究下ubuntu 配置hadoop ubuntu版本 64 bit 11 04 hadoop版本 hadoop1 2 1 一 在Ubuntu下创建hadoop用户组和用户 1 创建hadoop用户组 sudo addgroup
  • java动态加载jar包,并运行其中的类和方法

    flink 相关 https www toutiao com article 6883793897495986691 动态加载jar包 在实际开发中经常会需要用到 尤其涉及平台和业务的关系的时候 业务逻辑部分可以独立出去交给业务方管理 业务
  • java 泛型 作用与定义

    1 泛型方法的定义和使用 public static void main String args throws ClassNotFoundException String str get 哈士奇 world System out print
  • MVC模型图

    MVC图
  • Java学习13:面向对象-多态(Polymorphism)内存分析图解

    1 概述 多态是Java面向对象三大特征之一 多态 Polymorphism 顾名思义 即对象具有多种形态 具体而言 是编译时类型 运行时类型 编译时类型 由声明时的类型决定 一般是父类 运行时类型 由实际对应的对象类型决定 具体是哪个子类
  • jeecgboot问题解决方案

    常见问题Q A JEECG老版在线文档 点击进入 1 后台访问提示token错误 报错截图 解决方案 JeecgBoot后台的所有请求访问 增加了token机制 所以不能直接访问后台 而需要通过前台登录才能访问 默认前台访问地址 http
  • JAVA--GUI(2)--布局

    布局 为了更好适应不同平台而引入的概念 Java的布局管理器是一个实现了LayoutManager接口的实例 用户无法设置setLocation 这些方法 如果想自己设置则需要取消布局管理器 采用布局管理器 边界布局 顺序布局 网格布局 卡
  • IDEA 编写JDBC 第一个示例

    知心惟有雕梁燕 自来相伴 东风不管琵琶怨 落花吹遍 一 新建一个Module 二 在此Module下新建一个包 在包再建一个包 命名为lib 三 导入mysql驱动 四 将mysql驱动添加到项目的库里 五 代码实现 package Con
  • java基础之HashSet详解

    HashSet详解 HashSet是基于HashMap实现的一个单列存储的集合类 将所有的数据存在HashMap的key值中 而value全部使用一个Object对象存储 继承关系 public class HashSet

随机推荐

  • 【7-4 h0018.金币 (20 分)】思路清晰,c++实现,分分钟解决

    7 4 h0018 金币 20 分 国王以金币支付给他忠诚的骑士 在他服役的第一天 骑士会得到一枚金币 在接下来的每两天 服务的第二和第三天 骑士会收到两枚金币 在 在接下来的三天里 第四 第五和第六天 骑士每一天都会得到三枚金币 在接下来
  • HTML中怎么设置图片的位置和大小

    其他的也不多废话了直接上代码 img src fan jpg width 800 height 800
  • python批量爬取公众号文章

    前言 本文的文字及图片来源于网络 仅供学习 交流使用 不具有任何商业用途 版权归原作者所有 如有问题请及时联系我们以作处理 作者 舴艋的舟 PS 如有需要Python学习资料的小伙伴可以加点击下方链接自行获取 python免费学习资料以及群
  • js逆向:rpc远程调用

    websocket python代码 服务端 先开启这个 import asyncio import websockets connected set async def server websocket connected add web
  • Linux系统连接华为oceanstor数据存储

    Linux系统连接华为oceanstor数据存储 一 登录检查oceanstor数据存储 二 配置linux使用的数据储存 1 创建LUN 2 创建Lun组 3 创建主机 4 创建主机组 5 创建映射关系 三 Linux客户端操作 1 查看
  • 「建议收藏」Pycharm使用教程(非常详细,非常实用)

    Pycharm使用教程 1 Jetbrains家族和Pycharm版本划分 pycharm是Jetbrains家族中的一个明星产品 Jetbrains开发了许多好用的编辑器 包括Java编辑器 IntelliJ IDEA JavaScrip
  • Atcoder Beginner Contest 300

    A N choice question AC代码 include
  • 【Java基础11】面向对象、面向过程、类、对象、封装

    一 面向对象和面向过程 面向对象 以对象为单位 通过调度组合不同的对象来完成某一个功能 面向过程 以步骤为单位 一步一步完成某一个具体的功能 二 类 1 类的定义 class 类名 在类中定义属性 方法 class student Stri
  • pytorch 多个模型 求平均

    from collections import OrderedDict import torch from models faceland d import FaceLanndInference d if name main model F
  • Vite 打包体积分析,性能提升不再困扰

    其实这个问题最好改成 rollup 打包体积分析 但是为什么我会取这个名字呢 其实这主要是由于我的习惯性引起的 因为太久没用一个东西 如果遇到问题 肯定会去围绕它自身去进行搜索 例如遇到 vite 打包分析相关问题 就会在 google 搜
  • MinIO从信息泄漏到RCE

    文章目录 信息泄露 漏洞利用 漏洞分析 漏洞修复 RCE 漏洞分析 参考文章 信息泄露 漏洞利用 如果MinIO以集群方式部署 存在信息泄露漏洞 攻击者可以通过HTTP请求获取目标进程的所有环境变量 包括MINIO SECRET KEY和M
  • 计算机网络——分层的体系结构(OSI模型/五层协议栈)

    一 基础知识 计算机网络 计算机网络是一个非常复杂的系统 涉及许多组成部分 主机 hosts 路由器 routers 各种链路 links 应用 applications 协议 protocols 硬件 软件 网络体系结构的特点 1 网络体
  • [高级数据结构C++] 树状数组进阶(求逆序对的个数)

    算法竞赛 file author jUicE g2R qq 3406291309 彬 bin 必应 一个某双流一大学通信与信息专业大二在读 brief 一直在算法竞赛学习的路上 copyright 2023 9 COPYRIGHT 原创技术
  • ROS模型构建、定位导航

    利用URDF或者Xacro文件 以XML的方式描述小车底盘 camera laser Kinect等基本机器人结构 通过Gazebo或Rviz将文件解析为图形化的机器人模型 其中很多代码可以从网络上找到 主要注意参数和坐标系的设置 例如在K
  • CSS之美化网页 span标签 与 div标签

    CSS高级特性 我们大家在学习CSS之前 肯定已经接触过了HTML了吧 那么我们为什么还要学习CSS呢 首先哈 CSS可以有效的传递页面信息 使用CSS美化过的页面文本 非常漂亮 美观 并且可以突出重点 使用户看到页面的主要内容 具有良好的
  • UE4笔记-进程/线程/网络/IO模块的相关问题记录

    吐槽 如果有Qt的开发经验 会发现其实在比较底层编程理念UE4和Qt极其相识 很多类名和用法甚至都是相同的 Q 创建线程类 UE4文档没有特别介绍关于线程模块的文章 这里自己简单记录一下 备查 目前来说UE4的线程模块还是比较简陋的 命名风
  • 如果一个节点重新安装了,处理办法

    1 安装操作系统 如果可以最好所有的包都安装上 创建用户 组 更改核心参数 bash profile 2 配制ssh 保证新的结点和原有的节点互信 3 安装asmlib 然后用 etc init d oracleasm scandisks
  • Mybatis中的动态SQL

    Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能 它存在的意义是为了解决拼接SQL语句字符串时的痛点问题 一 if 单独使用较少 if标签可通过test属性 即传递过来的数据 的表达式进行判断 若表达式的结果为t
  • 单目3D检测-坐标系、数据集

    0 单目3D检测任务 c x y z w
  • JAVA基本数据类型与byte互相转换(位运算,原码,补码)

    最近整理了之前的一些知识 做了一个java中byte类型与int long转换以及将字节信息表示成字符串形式的工具 对前面的只是做了一下复习整理 原码 反码 补码 首先这三者都是二进制码即 0 1组合 原码 最高位为符号位 0表示正数 1表