[Java SE/计算机组成原理] Java 基本数值类型的底层存算原理、与二进制字节数据流的转换
序
- 关键词:原码、补码、反码
- 关键词: int / float(IEEE 754 单精度浮点数) / double(IEEE 754 双精度浮点数)
- 关键词: IEEE 754 浮点数
- 在
IEEE 754格式的浮点数由 3 个部分组成: 符号码,阶码,尾数码- IEEE754 浮点数:简读+案例=秒懂 - CSDN 【推荐】

概述
Int 与 Byte 数组的转换
intToBytes(int value)
/**
* Int 转 byte 数组
* @note
* 1. 原理:将 int 数据中的四个byte取出,分别存储
* 2. 辅助分析工具: {@link BytesUtils # intToHexString(xxxx) / hexStringToBinaryString(96) }
* 3. Java byte 取值范围是 [-128, +127]. Java中的 byte 数据类型是 8 位、有符号的,其取值范围是从 -128 到 127
* 3.1 在计算机内存存放的数值都是【补码】形式,第1位为符号位
* 3.2 在补码中,正数的补码与其原码相同
* 3.3 负数的补码是将其原码的每位取反后,再加1
* @sample
* 1. value=123, return=bytes[0, 0, 0, 123] = 0x00 00 00 7B = 0111 1011(BIN)
* 2. value=5674, return=bytes[0, 0, 22, 42] = 0x00 00 16 2A = 0001 0110 0010 1010(BIN)
* 3. value=9 999 999, return=bytes[0, -104, -106, 127] = 0x00 98 96 7F = 1001 1000 1001 0110 0111 1111(BIN)
* bytesToHexString( intToBytes(9999999) ) = "0098967f"
* 正整数 转 byte : 以整数 123 为例 => 0111 1011(BIN) = 0x7B
* 负整数 转 byte : 以整数 -104 为例 => 1001 1000(BIN) = 0x98
* 正整数 104 的原码 = 0110 1000
* 每位取反 = 1001 0111
* 再+1 = 1001 1000(BIN)
* @reference-doc
* [1] java基本数据类型byte的取值范围-128~127,以及溢出后取值的实现 - CSDN - https://blog.csdn.net/luzhensmart/article/details/107203110
* [2] 计算机编码方式:原码、反码、补码 - 博客园 - 18132824
* @param value
* @return
*/
public static byte[] intToBytes(int value) {
byte[] b = new byte[4];
for (int i = 0; i < 4; i++) {
b[i] = (byte) (value >> (24 - i * 8));
}
return b;
}
bytesToInt(byte [] bytes)
/**
* bytes 转 int
* 1个 byte 数据左移24位变成0x??000000,再右移8位变成0x00??0000
* @sample
* 1. bytes = [0, 0, 0, 123], return : 123
* @reference-doc
* [1] java byte数组和int互转 - Zhihu - https://zhuanlan.zhihu.com/p/580220308
* @param bytes
* @return
*/
public static int bytesToInt(byte [] bytes) {
int value = 0;
for (int i = 0; i < 4; i++) {
value <<= 8;// < < = 8
int b = bytes[i] & 0xFF; //
value |= b;// | = b
}
return value;
}
Float 与 Byte 数组的转换
在Java编程中,float 类型用于表示单精度浮点数,而 byte 数组则是用于存储原始的8位数据。
这两个数据结构虽然看似不同,但在某些场景下,它们可以相互转换,从而实现高效的数据存储和处理。
本章节将深入探讨Java中 float 和 byte 数组的相互转换,以及一些实用的存储与处理技巧。
Float类型简介
float 类型在Java中是一个32位的单精度浮点数,它遵循IEEE 754标准。float 类型在内存中的表示由三个部分组成:
- 符号位(1位):决定数值的正负。
- 指数部分(8位):存储指数值,通常以偏移形式表示。
- 尾数部分(23位):存储数值的有效数字。
float的取值范围
float 类型的取值范围大约在 3.4e-38 到 1.4e+38 之间,这比 int 类型要大得多,但精度较低。
byte数组简介
byte 数组是一个固定长度的字节数组,每个元素都是 byte 类型,即8位的数据。在Java中,byte 类型的取值范围是 -128 到 127。
float到byte数组的转换
将 float 转换为 byte 数组的过程涉及到将 float 的32位二进制表示提取出来,并将其存储在 byte 数组中。以下是一个简单的示例:
/**
* 浮点数转 byte 数组
* @note
* 1. 依据1: Java Float 共计 4 字节,32 bit
* 2. 原理: 将 float 数据中的 4个 byte 取出,分别存储
* @sample
* 1. value=1.23f , return
* = 0x3f 9d 70 a4 = bytes[63, -99 , 112, -92] = bytes[63, 157, 112, 164] (x)
* = 0011 1111 1001 1101 0111 0000 1010 0100(BIN)
* = 1067282596(DEC)
* 补充: bytesToHexString(new byte[] {63, -99 , 112, -92}) = "3f9d70a4"
* @param value
* @reference-doc
* @return
*/
public static byte[] floatToBytes(float value) {//eg: 1.23f
//1:float 转 byte 数组
int bits = Float.floatToIntBits(value);//eg: 1067282596(DEC)
byte[] bytes = new byte[4];
for (int i = 0; i < 4; i++) {
bytes[i] = (byte) ((bits >> (24 - (8 * i))) & 0xFF);
}
//2:字节序(byte order)与大小端的处理 : 略
// // 翻转数组
// int len = bytes.length;
// // 建立一个与源数组元素类型相同的数组
// byte[] dest = new byte[len];
// // 为了防止修改源数组,将源数组拷贝一份副本
// System.arraycopy(bytes, 0, dest, 0, len);
// byte temp;
// // 将顺位第i个与倒数第i个交换
// for (int i = 0; i < len / 2; ++i) {
// temp = dest[i];
// dest[i] = dest[len - i - 1];
// dest[len - i - 1] = temp;
// }
return bytes;//eg: 0x3f9d70a4
}
这个方法首先使用 Float.floatToIntBits() 方法将 float 转换为 int 类型的位表示,然后通过位运算将这32位数据分割成四个字节,并存储在 byte 数组中。
byte数组到float的转换
将 byte 数组转换回 float 的过程与上述相反。以下是一个示例:
/**
* bytes 转 Float
* @note
* 1. Java Float : 在Java中,float类型是单精度浮点数,遵循IEEE 754标准。
* 它占用4个字节(32位),由符号位、指数位和尾数位组成:
* 符号位(S):1 bit,表示正负,0为正,1为负。
* 指数位(E):8 bit,表示指数部分,范围为-126到127。
* 23-30位, 共 8 bit为指数位,这里指数的底数规定为 2 (取值范围:0-255)
* 这一部分的最终结果格式为: 2^{E-127}
* 尾数位(M):23 bit,表示小数部分。
* 2. float 的精度由尾数位决定,共23位。其有效小数位为6到7位,能保证6位为绝对精确,7位一般也是正确的,8位就不一定了
* @reference-doc
* [1] Java中float/double取值范围与精度 - CSDN - https://blog.csdn.net/a327369238/article/details/52354811
* @sample
* 1. bytes={63, -99 , 112, -92}
* = 0x3f 9d 70 a4 = bytes[63, 157, 112, 164] (x)
* = 0011 1111 1001 1101 0111 0000 1010 0100(BIN)
* = 1067282596(DEC)
* return = 1.23f
* 补充: bytesToHexString(new byte[] {63, -99 , 112, -92}) = "3f9d70a4"
* @param bytes
* @return
*/
public static float bytesToFloat(byte[] bytes) {
int bits = 0;
for (int i = 0; i < 4; i++) {
bits |= (bytes[i] & 0xFF) << (24 - (8 * i));
}
return Float.intBitsToFloat(bits);
}
这个方法通过循环遍历 byte 数组,使用位运算将每个字节转换回相应的位,并最终使用 Float.intBitsToFloat() 方法将位表示转换回 float。
存储与处理技巧
- 小端序和大端序:在将
float转换为byte数组时,需要考虑系统的小端序或大端序。在上面的示例中,我们假设系统是小端序。如果系统是大端序,那么字节顺序将相反。 - 数据精度:由于
float类型的精度限制,转换过程中可能会丢失一些精度。在进行高精度计算时,应考虑使用double类型。 - 内存效率:将
float存储为byte数组可以节省内存,尤其是在处理大量浮点数时。 - 性能优化:直接操作
byte数组通常比使用对象类型(如ByteBuffer)更快,因为它减少了对象的创建和垃圾回收。
通过理解 float 和 byte 数组之间的转换,以及相关的存储和处理技巧,Java开发者可以更有效地管理和处理数据,提高应用程序的性能和效率。
Double 与 Byte 数组的转换
doubleToBytes
/**
* Double 转 bytes
* @sample
* 1. value=123.56
* return = [-92, 112, 61, 10, -41, -29, 94, 64]
* = 0xa4703d0ad7e35e40
* @param value
* @return
*/
public static byte[] doubleToBytes(double value) {
long longBits = Double.doubleToRawLongBits(value);
byte[] byteRet = new byte[8];
for (int i = 0; i < 8; i++) {
byteRet[i] = (byte) ((longBits >> 8 * i) & 0xff);
}
return byteRet;
}
bytesToDouble
/**
* bytes 转 Double
* @sample
* 1. bytes=[-92, 112, 61, 10, -41, -29, 94, 64] = 0xa4703d0ad7e35e40
* return = 123.56
* @param bytes
* @return
*/
public static double bytesToDouble(byte[] bytes) {
long value = 0;
for (int i = 0; i < 8; i++) {
value |= ((long) (bytes[i] & 0xff)) << (8 * i);
}
return Double.longBitsToDouble(value);
}
Y 推荐文献
int转字节数组 大端模式 / int转字节数组 小端模式
字节数组转int 大端模式 / 字节数组转int 小端模式

X 参考文献
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!

浙公网安备 33010602011771号