当前位置: 首页 > article >正文

Java基本数据类型与字节数组的相互转换

C/C++的相互转换

作为一名C/C++语言开发者,熟悉各种数据类型的底层表示,很容易就会把它们的内存地址直接进行字节型的读写。

比如我们定义了一个int的类型,在不考虑大小端的情况下,就可以直接通过按照变量地址进行读写:

// 写入一个int值到unsigned char *
void writeInt(int iv, unsigned char *p, size_t psize) 
assert (sizeof (iv) <= psize);
memcpy (p, &iv, sizeof (iv));
}

// 读取一个unsigned char *到int
void readInt(int *iv, const unsigned char *p, size_t psize)
{
assert (psize >= sizeof (*iv));
*iv = * (int *) p;
}

通过DataInputStream与DataOutputStream

在Java中,这一点却没有那么简单直接。

因为Java一切皆对象,这些对象有的是值类型,有的是指针类型,但是无论是什么类型,都不支持直接对底层内存地址的数据进行读写。

虽然,比较新的Java有unsafe实现,但是unsafe也只能对对象的属性,进行偏移量级别的读写,仍然没法对底层的数据进行操作。

好在作为一个非常成熟的语言,Java在这方面包装了各种类来实现。其中,DataInputStream/DataOutputStream就是一个读写数据类型的好方法(虽然性能不佳)。

DataInputStream是DataInput接口的一个实现。为了篇幅简短,以下是DataInput去掉注释以后的源代码:

public interface DataInput {

void readFully(byte[] b) throws IOException;

void readFully(byte[] b, int off, int len) throws IOException;

int skipBytes(int n) throws IOException;

boolean readBoolean() throws IOException;

byte readByte() throws IOException;

int readUnsignedByte() throws IOException;

short readShort() throws IOException;

int readUnsignedShort() throws IOException;

char readChar() throws IOException;

int readInt() throws IOException;

long readLong() throws IOException;

float readFloat() throws IOException;

double readDouble() throws IOException;

String readLine() throws IOException;

String readUTF() throws IOException;

}

DataInputStream类是一个包装类,可以包装在底层的InputStream上。如果包装一个ByteArrayInputStream,就可以实现对byte[]的读取了。

同理,使用DataOutputStream包装在ByteArrayOutputStream上,就可以实现对byte[]的写入。

因为DataOutputStream实现了DataOutput接口。与DataInput类似,DataOutput接口如下:

public interface DataOutput {

void write(int b) throws IOException;

void write(byte[] b) throws IOException;

void write(byte[] b, int off, int len) throws IOException;

void writeBoolean(boolean v) throws IOException;

void writeByte(int v) throws IOException;

void writeShort(int v) throws IOException;

void writeChar(int v) throws IOException;

void writeInt(int v) throws IOException;

void writeLong(long v) throws IOException;

void writeFloat(float v) throws IOException;

void writeDouble(double v) throws IOException;

void writeBytes(String s) throws IOException;

void writeChars(String s) throws IOException;

void writeUTF(String s) throws IOException;

}

以下两个函数片段演示了具体的数据类型与字节数组的交互:

    public byte[] ToByteArray() throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
        dataOutputStream.writeBoolean(true);
        dataOutputStream.writeByte(1);
        dataOutputStream.writeShort(1);
        dataOutputStream.writeInt(1);
        dataOutputStream.writeLong(1);
        dataOutputStream.writeFloat(1.0f);
        dataOutputStream.writeDouble(1.0d);
        dataOutputStream.writeUTF("hello,world");
        byteArrayOutputStream.close();
        return byteArrayOutputStream.toByteArray();
    }

    public void fromByteArray(byte[] bytes) throws IOException {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
        boolean bo = dataInputStream.readBoolean();
        byte b = dataInputStream.readByte();
        short s = dataInputStream.readShort();
        int i = dataInputStream.readInt();
        long l = dataInputStream.readLong();
        float f = dataInputStream.readFloat();
        double d = dataInputStream.readDouble();
        String str = dataInputStream.readUTF();
        dataInputStream.close();
    }

通过ByteBuffer

伴随NIO一起被引入Java语言的,还有ByteBuffer。

ByteBuffer是方便做io的缓冲区读写的,我们可以使用它的读写基本类型的接口,来完成byte[]的操作。

比如,我们如果要把基本类型转成byte[],可以先按照每种类型的大小,创建一个ByteBuffer,然后设置值之后,返回它的arrry,即byte[]。

以下是short、int、long、float、double转成byte[]的转换函数:

    public static byte[] shortToBytes(short s) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(Short.BYTES);
        byteBuffer.putShort(s);
        return byteBuffer.array();
    }

    public static byte[] intToBytes(int i) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(Integer.BYTES);
        byteBuffer.putInt(i);
        return byteBuffer.array();
    }

    public static byte[] longToBytes(long l) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(Long.BYTES);
        byteBuffer.putLong(l);
        return byteBuffer.array();
    }
    
    public static byte[] floatToBytes(float f) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(Float.BYTES);
        byteBuffer.putFloat(f);
        return byteBuffer.array();
    }
    
    public static byte[] doubleToBytes(double d) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(Double.BYTES);
        byteBuffer.putDouble(d);
        return byteBuffer.array();
    }

如果要反过来转化,则可以先把确定大小的byte[]数组,转成ByteBuffer,之后再调用ByteBuffer的读取方法。

如:

    public static short shortFromBytes(byte[] bytes) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
        return byteBuffer.getShort();
    }

    public static int intFromBytes(byte[] bytes) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
        return byteBuffer.getInt();
    }

    public static long longFromBytes(byte[] bytes) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
        return byteBuffer.getLong();
    }

    public static float floatFromBytes(byte[] bytes) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
        return byteBuffer.getFloat();
    }

    public static double doubleFromBytes(byte[] bytes) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
        return byteBuffer.getDouble();
    }

直接转化

上面两种转换方法,都引入了中间对象,有了对象创建与释放的开销,如果追求高性能,还是直接转化比较简单直接。

因为short、int、long类型,不像浮点数那样,有具体语言实现的存储方式,所以可以直接按照字节做运算转化。而float、double都有转换成int、long的实现,可以先转换成int、long再转化成byte[]。

比如:

public static byte[] directShortToBytes(short s) throws IOException {  
    byte[] bytes = new byte[Short.BYTES];  
    bytes[0] = (byte) (s >> 8 & 0xFF);  
    bytes[1] = (byte) (s & 0xFF);  
    return bytes;  
}  
  
public static byte[] directIntToBytes(int i) throws IOException {  
    byte[] bytes = new byte[Integer.BYTES];  
    bytes[0] = (byte) (i >> 24 & 0xFF);  
    bytes[1] = (byte) (i >> 16 & 0xFF);  
    bytes[2] = (byte) (i >> 8 & 0xFF);  
    bytes[3] = (byte) (i & 0xFF);  
    return bytes;  
}  
  
public static byte[] directLongToBytes(long l) throws IOException {  
    byte[] bytes = new byte[Long.BYTES];  
    bytes[0] = (byte) (l >> 56 & 0xFF);  
    bytes[1] = (byte) (l >> 48 & 0xFF);  
    bytes[2] = (byte) (l >> 40 & 0xFF);  
    bytes[3] = (byte) (l >> 32 & 0xFF);  
    bytes[4] = (byte) (l >> 24 & 0xFF);  
    bytes[5] = (byte) (l >> 16 & 0xFF);  
    bytes[6] = (byte) (l >> 8 & 0xFF);  
    bytes[7] = (byte) (l & 0xFF);  
    return bytes;  
}  
  
public static byte[] directFloatToBytes(float f) throws IOException {  
    int i = Float.floatToIntBits(f);  
    return directIntToBytes(i);  
}  
  
public static byte[] directDoubleToBytes(double d) throws IOException {  
    long l = Double.doubleToLongBits(d);  
    return directLongToBytes(l);  
}  

以下是相反的实现:

public static short directShortFromBytes(byte[] bytes) throws IOException {  
    short s = (short) (bytes[0] << 8);  
    s += bytes[1];  
    return s;  
}  
  
public static int directIntFromBytes(byte[] bytes) throws IOException {  
    int i = bytes[0] << 24;  
    i += bytes[1] << 16;  
    i += bytes[2] << 8;  
    i += bytes[3];  
    return i;  
}  
  
public static long directLongFromBytes(byte[] bytes) throws IOException {  
    long l = ((long) bytes[0]) << 56;  
    l += ((long) bytes[1]) << 48;  
    l += ((long) bytes[2]) << 40;  
    l += ((long) bytes[3]) << 32;  
    l += bytes[4] << 24;  
    l += bytes[5] << 16;  
    l += bytes[6] << 8;  
    l += bytes[7];  
    return l;  
}  
  
public static float directFloatFromBytes(byte[] bytes) throws IOException {  
    int i = directIntFromBytes(bytes);  
    return Float.intBitsToFloat(i);  
}  
  
public static double directDoubleFromBytes(byte[] bytes) throws IOException {  
    long l = directLongFromBytes(bytes);  
    return Double.longBitsToDouble(l);  
}

http://www.kler.cn/a/466394.html

相关文章:

  • java.lang.Error: FFmpegKit failed to start on brand:
  • 科研绘图系列:R语言科研绘图之标记热图(heatmap)
  • Linux 基础七 内存
  • 3D Object Detection和6D Pose Estimation有什么异同?
  • CSP初赛知识学习计划
  • 『SQLite』详解运算符
  • JAVA复习题
  • 使用docker desktop提示 需要更新WSL
  • 深入理解 Android 中的 ApplicationInfo
  • 深入Android架构(从线程到AIDL)_07 线程(Thread) 概念
  • 利用Claude3.5点评学习LightRAG源码
  • css中的渐变
  • 学技术学英文:Tomcat的线程模型调优
  • 基于 GitHub API 的 Issue 和 PR 自动化解决方案
  • ArcGIS API for JavaScript 缓冲区分析、河涌关联分析、集中连片分析
  • 高速网络数据包处理中的内核旁路技术
  • Ae 效果详解:漩涡条纹
  • .NET 8 + Ocelot + Consul 实现代理网关、服务发现
  • 365天深度学习训练营:第N1周:one-hot编码案例
  • 【Unity3D】LOD Group 多细节层次(CrossFade淡出淡入效果)
  • java: JDK isn‘t specified for module ‘product-service‘问题解决
  • 大数据-269 实时数仓 - DIM DW ADS 层处理 Scala实现将数据写出HBase等
  • 阅读线程池源码中遇到的retry:
  • 密码学精简版
  • 打靶记录24——Presidential
  • 【JavaScript】变量-常量-数据类型-类型转换