Java 中字节数组和基本类型之间的相互转换

社会性死亡

碰到需要在基本类型数据和字节数组之间相互转换的问题,但我查了基础类型的包装类,似乎没有可用的方法;使用 IO 流又不够装X,所以干脆搞个工具类,里面写些相互转换的方法,后续使用起来也比较方便。

工具类源码:

import java.io.*;

/**
 * 此工具类用于字节数组和基本数据类型之间的互相转换
 * java中储存数据的方式是大端字节序,高位字节在前,低位字节在后,这是人类读写数值的习惯方法。
 * 以下所有的操作都是针对的大端字节序
 */
public class ByteArrayUtils {
    
    //分析int转byte[]
    public static byte[] testIntToByteArray(int value) {
        //int占4个字节
        byte[] bytes = new byte[4];
        /**
         * 使用>>位移运算符,并强转byte依次取得高位字节
         * 由于是大端字节序,高位到低位是从左到右
         * 例如 int num = 0x060A0B02,高位到低位依次是:06 -> 0A -> 0B -> 02
         * 这个int类型变量的值的16进制为:06 0A 0B 02
         */
        //右移24位后,返回值00 00 00 06,强转之后变成06
        bytes[0] = (byte) (value >> 24);
        //右移16位后,返回值00 00 06 0A,强转之后变成0A
        bytes[1] = (byte) (value >> 16);
        //右移16位后,返回值00 06 0A 0B,强转之后变成0B
        bytes[2] = (byte) (value >> 8);
        //06 0A 0B 02,强转之后变成02
        bytes[3] = (byte) value;
        return bytes;
    }
    
    //分析byte[]转int
    public static int testByteArrayToInt(byte[] bytes) {
        /**
         * byte类型的数字要&0xFF再赋值给int类型,
         * 其本质原因就是想保持二进制补码(负数用补码表示)的一致性
         */
        int ff = 0xFF; //00 00 00 FF
        //假设字节数组为 06 0A 0B 02
        //左移24位之后,h0为06 00 00 00
        int h0 = (bytes[0] & ff) << 24;
        //左移16位之后,h1为00 0A 00 00
        int h1 = (bytes[1] & ff) << 16;
        //左移8位之后,h2为00 00 0B 00
        int h2 = (bytes[2] & ff) << 8;
        //h3为00 00 00 02
        int h3 = bytes[3] & ff;
        
        int value = h0 | h1 | h2 | h3;
        return value;
    }
    
    /**
     * short转byte[]
     * @param value
     * @return byte[]
     */
    public static byte[] shortToByteArray(short value){
        byte[] bytes = new byte[2];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) (value >> (bytes.length - i - 1) * 8);
        }
        return bytes;
    }
    
    /**
     * byte[]转short
     * @param bytes
     * @return short
     */
    public static short byteArrayToShort(byte[] bytes){
        int ff = 0xFF;
        short value = 0;
        for (int i = 0; i < bytes.length; i++) {
            value |= (bytes[i] & ff) << (bytes.length - i - 1) * 8;
        }
        return value;
    }
    
    /**
     * int转byte[]
     * @param value
     * @return byte[]
     */
    public static byte[] intToByteArray(int value) {
        byte[] bytes = new byte[4];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) (value >> (bytes.length - i - 1) * 8);
        }
        return bytes;
    }
    
    /**
     * byte[]转int
     * @param bytes
     * @return int
     */
    public static int byteArrayToInt(byte[] bytes) {
        int ff = 0xFF;
        int value = 0;
        for (int i = 0; i < bytes.length; i++) {
            value |= (bytes[i] & ff) << (bytes.length - i - 1) * 8;
        }
        return value;
    }
    
    /**
     * long转byte[]
     * @param value
     * @return byte[]
     */
    public static byte[] longToByteArray(long value){
        byte[] bytes = new byte[8];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) (value >> (bytes.length - i - 1) * 8);
        }
        return bytes;
    }
    
    /**
     * byte[]转long
     * @param bytes
     * @return long
     */
    public static long byteArrayToLong(byte[] bytes){
        int ff = 0xFF;
        long value = 0;
        for (int i = 0; i < bytes.length; i++) {
            value |= (bytes[i] & ff) << (bytes.length - i - 1) * 8;
        }
        return value;
    }
    
    /**
     * float转byte[]
     * @param value
     * @return byte[]
     */
    public static byte[] floatToByteArray(float value){
        int bitLayoutIntValue = Float.floatToIntBits(value);
        byte[] bytes = new byte[4];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) (bitLayoutIntValue >> (bytes.length - i - 1) * 8);
        }
        return bytes;
    }
    
    /**
     * byte[]转float
     * @param bytes
     * @return float
     */
    public static float byteArrayToFloat(byte[] bytes){
        int ff = 0xFF;
        int bitLayoutIntValue = 0;
        for (int i = 0; i < bytes.length; i++) {
            bitLayoutIntValue |= (bytes[i] & ff) << (bytes.length - i - 1) * 8;
        }
        return Float.intBitsToFloat(bitLayoutIntValue);
    }
    
    /**
     * double转byte[]
     * @param value
     * @return byte[]
     */
    public static byte[] doubleToByteArray(double value){
        long bitLayoutLongValue = Double.doubleToLongBits(value);
        byte[] bytes = new byte[8];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) (bitLayoutLongValue >> (bytes.length - i - 1) * 8);
        }
        return bytes;
    }
    
    /**
     * byte[]转double
     * @param bytes
     * @return double
     */
    public static double byteArrayToDouble(byte[] bytes){
        long ff = 0xFF;
        long bitLayoutLongValue = 0;
        for (int i = 0; i < bytes.length; i++) {
            bitLayoutLongValue |= (bytes[i] & ff) << (bytes.length - i - 1) * 8;
        }
        return Double.longBitsToDouble(bitLayoutLongValue);
    }
    
    /**
     * 文件转byte[],IO流
     * @param file
     * @return byte[]
     */
    public static byte[] fileToByteArray(File file) {
        byte[] dest = null;
        InputStream is = null;
        try {
            is = new BufferedInputStream(new FileInputStream(file));
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] flushBuffer = new byte[1024];
            int readLen = -1;
            while ((readLen = is.read(flushBuffer)) != -1) {
                baos.write(flushBuffer, 0, readLen);
            }
            baos.flush();
            dest = baos.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return dest;
    }
    
    /**
     * byte[]转文件,IO流
     * @param src
     * @param dest
     */
    public static void byteArrayToFile(byte[] src, File dest) {
        OutputStream os = null;
        try {
            os = new BufferedOutputStream(new FileOutputStream(dest));
            InputStream is = new ByteArrayInputStream(src);
            byte[] flushBuffer = new byte[1024];
            int readLen = -1;
            while ((readLen = is.read(flushBuffer)) != -1) {
                os.write(flushBuffer, 0, readLen);
            }
            os.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

上面代码中头两个方法是测试分析 int 和 byte[] 之间的相互转换的,一通百通,弄明白 int 类型,那么剩下的其他基本类型的转换也就简单了。

这里值得注意是 float 和 double,转换时需要用到其包装类的 native 方法,以 double 为例,Double.longBitsToDouble(bitLayoutLongValue) 是将 8 位 long 类型整数按照其位布局转换为相应的 double 浮点数;Double.doubleToLongBits(value) 是按照 double 类型的浮点数的位布局转换为 long 整数。float 类似。

float 占 4 个字节,int 也占 4 个字节,刚好可以把某个 float 的位布局看作一个 int 类型的整数;double 占 8 个字节,long 也占 8 个字节,刚好可以把某个 doube 的位布局看作一个 long 类型的整数。

还有一点需要注意的是 byte & 0xFF 这个骚操作了,如果转换的基本类型是个负数,那么 & 0xFF 就很有必要了。

当 byte 类型的负数自动转化为 int 类型参与运算时,高的 24 位必然会补 1,这样,其二进制补码其实已经不一致了,& 0xFF 可以将高的 24 位“清算”为 0,低 8 位保持原样。这样做的目的就是为了保证二进制数据的一致性。

试运行下面代码:

public static void main(String[] args) {
    int num = -0x060A0B02;
    System.out.println(num);
    System.out.println();
    byte[] bytes = ByteArrayUtils.intToByteArray(num);
    for (int i = 0; i < bytes.length; i++) {
        System.out.println(bytes[i]);
    }
}

运行结果:

-101321474

-7
-11
-12
-2

人脑外加手动分析:

-101321474

-7 --> 0000 0111 --> 1111 1111 1111 1111 1111 1111 1111 1001
                                        &
                     0000 0000 0000 0000 0000 0000 1111 1111 -->

                     0000 0000 0000 0000 0000 0000 1111 1001
                                       <<24
                 --> 1111 1001 0000 0000 0000 0000 0000 0000 --> int t0


-11 --> 0000 1011 --> 1111 1111 1111 1111 1111 1111 1111 0101
                                         &
                      0000 0000 0000 0000 0000 0000 1111 1111 -->

                      0000 0000 0000 0000 0000 0000 1111 0101
                                        <<16
                  --> 0000 0000 1111 0101 0000 0000 0000 0000 --> int t1


-12 --> 0000 1100 --> 1111 1111 1111 1111 1111 1111 1111 0100
                                         &
                      0000 0000 0000 0000 0000 0000 1111 1111 -->

                      0000 0000 0000 0000 0000 0000 1111 0100
                                        <<8
                  --> 0000 0000 0000 0000 1111 0100 0000 0000 --> int t2


-2 --> 0000 0010 --> 1111 1111 1111 1111 1111 1111 1111 1110
                                        &
                     0000 0000 0000 0000 0000 0000 1111 1111 -->

                     0000 0000 0000 0000 0000 0000 1111 1110 --> int t3


t0 | t1 | t2 | t3 --> 1111 1001 1111 0101 1111 0100  1111 1110
                  --> int value = -101321474 = -0x060A0B02

& 0xFF 在很多场合都有很大作为,这里需要引起我们的注意!

小小总结,到此为止。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容