[Java SE/计算机组成原理] Java 基本数值类型的底层存算原理、与二进制字节数据流的转换

  • 关键词:原码、补码、反码
  • 关键词: int / float(IEEE 754 单精度浮点数) / double(IEEE 754 双精度浮点数)
  • 关键词: IEEE 754 浮点数

概述

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中 floatbyte 数组的相互转换,以及一些实用的存储与处理技巧。

Float类型简介

float 类型在Java中是一个32位的单精度浮点数,它遵循IEEE 754标准。float 类型在内存中的表示由三个部分组成:

  1. 符号位(1位):决定数值的正负。
  2. 指数部分(8位):存储指数值,通常以偏移形式表示。
  3. 尾数部分(23位):存储数值的有效数字。

float的取值范围

float 类型的取值范围大约在 3.4e-381.4e+38 之间,这比 int 类型要大得多,但精度较低。

byte数组简介

byte 数组是一个固定长度的字节数组,每个元素都是 byte 类型,即8位的数据。在Java中,byte 类型的取值范围是 -128127

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

存储与处理技巧

  1. 小端序和大端序:在将 float 转换为 byte 数组时,需要考虑系统的小端序或大端序。在上面的示例中,我们假设系统是小端序。如果系统是大端序,那么字节顺序将相反。
  2. 数据精度:由于 float 类型的精度限制,转换过程中可能会丢失一些精度。在进行高精度计算时,应考虑使用 double 类型。
  3. 内存效率:将 float 存储为 byte 数组可以节省内存,尤其是在处理大量浮点数时。
  4. 性能优化:直接操作 byte 数组通常比使用对象类型(如 ByteBuffer)更快,因为它减少了对象的创建和垃圾回收。

通过理解 floatbyte 数组之间的转换,以及相关的存储和处理技巧,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 参考文献

posted @ 2025-04-16 00:40  千千寰宇  阅读(64)  评论(0)    收藏  举报