日常使用中, 存在一些场景需要把java对象转为字节数组。 或者字节数组转java对象。 一般来说有以下几种场景。
我们来分别讨论。
1. JAVA之间相互通讯场景
这种场景常见于java应用之间的通讯, 比如A应用向B应用获取数据。 或者读取B应用预先存的数据。
此时一般来说实体类实现java自带的序列化接口, 然后使用以下方式即可完成序列化。
private Object byteToObject( byte[] bytes) {
java.lang.Object obj;
try {
//bytearray to object
ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
ObjectInputStream oi = new ObjectInputStream(bi);
obj = oi.readObject();
bi.close();
oi.close();
}
catch(Exception ae) {
throw ae;
}
return obj;
}
public byte[] objectToByte(Object obj)
{
byte[] bytes;
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(obj);
bytes = bo.toByteArray();
bo.close();
oo.close();
}
catch(Exception ae) {
throw ae;
}
return(bytes);
}
此种方式适合java语言之间的通讯或者数据交互。不适合跨语言。而且也不适合于IM场景。
2. 仅仅做数据储存方案
储存方案一般来说要区分是否跨语言, 数据储存体积, 读取效率等问题。 这种建议优先采用文本化协议比较好(比如json, xml等), 方便开发者校验和开发。 如果使用二进制储存, 虽然体积小了。但是不方便开发和核对。出了bug不方便排查。
3. 跨语言通讯场景
跨语言通讯场景一般是最多的, 比如物联网。 IM通讯, 视频等等。由于业务的特殊性,所以一般会采用二进制协议。而且是私有协议居多。在进行序列化时候。java自带的序列化机制并不能很好的满足我们的需求。这个时候就需要用户自己手动进行序列化过程。
主要使用到 java的 ByteBuffer.
public class Student {
byte height;
int age;
long phone;
}
public static void main(String[] args) {
Student student = new Student();
student.height = (byte) 185;
student.age = 23;
student.phone = 18380330237L;
// 对象序列化到字节数组
ByteBuffer byteBuffer = ByteBuffer.allocate(100).order(ByteOrder.BIG_ENDIAN);
byteBuffer.put(student.height);
byteBuffer.putInt(student.age);
byteBuffer.putLong(student.phone);
byte[] array = byteBuffer.array();
// 字节数组序列化到对象
byteBuffer = ByteBuffer.allocate(100).order(ByteOrder.BIG_ENDIAN);
byteBuffer.put(array);
byteBuffer.position(0);
Student student2 = new Student();
student2.height = byteBuffer.get();
student2.age = byteBuffer.getInt();
student2.phone = byteBuffer.getLong();
}
上面的代码中, 列举出了我们平时序列化的方式。虽然使用字节数组可以高效率的完成对象的封装和转换。 但是需要注意以下问题:
- 字节数组大小端双方一定要一致
- 如果存在list, array 等属性, 要注意OOM
- buffer使用时如果时directbuffer, 需要注意OOM
- 注意序列化时空指针和默认值的处理
- 序列化数组不全时,注意数据对齐进行填补
- 处理 字符串时,注意字符编码集
其实跨语言通讯和私有协议这种场景,大都是大厂最先遇到并提出解决方案的。比如google 的 javastruct(2004年就出来了); 或者 magic-byte;
如果使用框架,以上的代码可以如下写了(注意类的定义和上面有所不同):
@MagicClass(byteOrder = ByteOrder.BIG_ENDIAN)
public class Student {
@MagicField(order = 1)
byte height;
@MagicField(order = 2)
int age;
@MagicField(order = 3)
long phone;
// gettter setter
}
public static void main(String[] args) {
Student student = new Student();
student.height = (byte) 185;
student.age = 23;
student.phone = 18380330237L;
// 对象序列化到字节数组
byte[] array = MagicByte.unpackToByte(student);
// 字节数组序列化到对象
Student student2 = MagicByte.pack(array, Student.class);
}
在定义类时, 即把序列化方式定义完成。然后只需要调用函数即可进行序列化和反序列化了。
怎么样, 这样是不是简单多了。
附上开源项目的地址:
以上就是总结的一些java 对象转字节的方式。 大家按需索取吧。
版权声明:本文为jioulongzi原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。