可能最先接触的序列化莫过于就是学习io 的时候讲的Objectoutputstream /ObjectInputStream 了把, 实现serizlize 接口,这种方式是方便,但是他的效率,从内存占用来说确实不佳 ,我们这次拿java 的序列化,和google 提供的protobuf 比较, 算了把说说概念,什么是序列化在java 中?
序列化 : 把一个对象转换为2 字节数组,
反序列化就反过来嘛,序列化用于网络传输,tcp 传输的是2进制数字,对象如果想经过网路传输,比如经过序列化,如果用java api 提供的话就是实现serialize 接口我们先用 java 提供的api 序列化一次对象,代码如下
java Api Serialize
package com.zzq.serialize.java;
import java.io.Serializable;
import java.util.List;
/**
* @author ZZQ
* @date 2018/8/12 9:00
*/
public class Person implements Serializable{
private String name ;
private Integer age ;
private String sex ;
public Person(String name, Integer age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
package com.zzq.serialize.java;
import java.io.*;
import java.util.Arrays;
/**
* @author ZZQ
* @date 2018/8/12 8:59
* 传统java 的序列化
*/
public class Sserialize_java {
public static void main(String[] args) throws Exception {
byte[] bytes = Object2ByteArray();
Person person = byteArray2Object(bytes);
}
public static byte[] Object2ByteArray() throws Exception{
Person person = new Person("jack", 12, "男");
ByteArrayOutputStream byteoutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteoutputStream);
//把对象写入byteoutputStream 中
objectOutputStream.writeObject(person);
//获取字节数组
byte[] byteArray = byteoutputStream.toByteArray();
System.out.println(Arrays.toString(byteArray));
System.out.println(byteArray.length);
objectOutputStream.close();
byteoutputStream.close();
return byteArray;
}
public static Person byteArray2Object(byte[] arr) throws Exception{
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(arr) ;
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
Person p =(Person) objectInputStream.readObject();
System.out.println(p);
return p ;
}
}
结果如下
我们可以看到用java 提供的api 实现序列化, 他的bytearray数组的长度是207 ,反序列化一切正常
protobuf serialize
ptotobuf 我感觉没有java 提供的api 简单使用,他首先要写proto 文件,然后通过程序生成java 对象,然后操作java 对象进行序列化,
说说proto 的语法把:
option java_package = "com.proto";
通过option java_package 定义包名, 这个东西对应生成java 对象的包名
option java_outer_classname = "PlayerModule";
option java_outer_classname 定义类名
注意: 这里的类名不是要序列化的对象的类名,是生成的java 文件的类名,该类中包含了要序列化的对象, 也就是你要使用的对象
然后我们来编写javabean
message PBPlayer{
required int64 playerId = 1;
required int32 age = 2;
required string name = 3;
repeated int32 skills = 4;
}
一个java 对象用message 定义, 相当于java 中的class 吧 ,
required 望文生义,这个就不言而喻了,意思就是必须赋值,不赋值就无法进行序列化,
int 32 64 这些参照这个表
.proto类型 | Java 类型 | C++类型 | 备注 |
---|---|---|---|
double | double | double | |
float | float | float | |
int32 | int | int32 | 使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数,那么请使用sint32。 |
int64 | long | int64 | 使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数,那么请使用sint64。 |
uint32 | int[1] | uint32 | Uses variable-length encoding. |
uint64 | long[1] | uint64 | Uses variable-length encoding. |
sint32 | int | int32 | 使用可变长编码方式。有符号的整型值。编码时比通常的int32高效。 |
sint64 | long | int64 | 使用可变长编码方式。有符号的整型值。编码时比通常的int64高效。 |
fixed32 | int[1] | uint32 | 总是4个字节。如果数值总是比总是比228大的话,这个类型会比uint32高效。 |
fixed64 | long[1] | uint64 | 总是8个字节。如果数值总是比总是比256大的话,这个类型会比uint64高效。 |
sfixed32 | int | int32 | 总是4个字节。 |
sfixed64 | long | int64 | 总是8个字节。 |
bool | boolean | bool | |
string | String | string | 一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。 |
bytes | ByteString | string | 可能包含任意顺序的字节数据。 |
目前 protobuf 提供三种语言支持 java py cpp 然后我把代码呈上
option java_package = "com.proto";
option java_outer_classname = "PlayerModule";
message PBPlayer{
required int64 playerId = 1;
required int32 age = 2;
required string name = 3;
repeated int32 skills = 4;
}
message PBResource{
required int64 gold = 1;
required int32 energy = 2;
}
package com.zzq.serialize.protobuf;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* @author ZZQ
* @date 2018/8/12 9:20
* 使用protobuf 序列化
*/
public class serialize {
public static void main(String[] args) throws Exception{
byte[] bytes = Object2ByteArray();
byteArrayToObject(bytes);
}
public static byte[] Object2ByteArray() throws Exception{
// 获取一个pbplayer构造器
PlayerModule.PBPlayer.Builder builder = PlayerModule.PBPlayer.newBuilder();
//设置数据
builder.setAge(12).setName("jack").setPlayerId(110).addSkills(110);
//构造出对象
PlayerModule.PBPlayer build = builder.build();
//序列化生成数组
byte[] byteArray = build.toByteArray();
System.out.println(Arrays.toString(byteArray));
System.out.println(byteArray.length);
return byteArray;
}
public static void byteArrayToObject(byte[] bytes) throws Exception{
PlayerModule.PBPlayer pbPlayer = PlayerModule.PBPlayer.parseFrom(bytes);
System.out.println(pbPlayer);
}
}
结果i如下
大家可以看到 12 序列化后的bytearray 为12 相比 java 的api 他的内存占用小,内存占用小, 带宽占用的就少,大量的数据传输来说,同时间可以传输更多,效率就高
谢谢!