序列化与反序列化
序列化
序列化:将对象转化成特定的形态,然后以数据流的形式进行传输。
序列化格式:XML、Json
序列化过程:Object -> Json -> 传输(json字符串转化的数据流)
序列化目的:减少对象的大小,实现对象的跨平台,跨语言传输
反序列化
反序列化过程:数据流 -> Json -> Object
序列化Demo
服务端:
public static void main (String[] args) {
ServiceSocket serviceSocket = new ServiceSocket(8080);
Socket socket = serviceSocket.accept();
ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
User user = (User)inputStream.readObject();
……
}
客户端:
public static void main (String args) {
Socket socket = new Socket("localhost", 8080);
ObjectOutputStream outputStream = new ObjectOutinputStream(socket.getOutputStream());
User user = new User();
user.setName("Tom");
outputStream.writer(user);
outputStream.flush();
}
对象:
public class User implements Serializable {
private String name:
public void setName(String name) {
this.name = name;
}
public String getName(){
return name;
}
}
Java中的序列化与反序列化
SerializableDemo
Serializable接口:
public instance ISerializable {
//序列化
<T> byte[] serialize(T object);
//反序列化
<T> T deSerialize(byte[] data);
}
Serializable接口的实现类:
public class JavaSerialize implements ISerializable {
@Override
public <T> byte[] serialize (T object) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
ObjectOutputStream outputStream = new ObjectOutputStream(byteArrayOutputStream);
outputStream.writerObject(objject);
return byteArrayOutPutStream.toByteArrray();
} catch (Execption e) {
e.printStackTrace();
}
return new byte[0];
}
@Override
public <T> T deSerialize (byte[] data) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputSteam(data);
try{
ObjectInputStream objectInputStream = new ObjectInputSteam(byteArrayInputStream);
return (T)objectInputStream.readObject();
} catch(Exception e) {
e.printStackTrace();
}
return null;
}
}
Serializable测试:
public static void main(String[] args) {
User user = new User();
user.setName("Tom");
//将User进行序列化
ISerializer serializer = new JavaSerializer();
byte[] bytes = serializer.serialize(user);
//反序列化
User userRever = serializer.deSerialize(bytes);
}
serialVersionUID
用于确保类序列化与反序列化的兼容性问题的,如果序列化和反序列化过程中这两个值不一样,那么将导致序列化失败
serialVersionUID发生改变的三种情况:
- 手动去修改导致当前的 serialVersionUID 与序列化前的不一样。
- 我们根本就没有手动去写这个 serialVersionUID 常量,那么 JVM 内部会根据类结构去计算得到这个 serialVersionUID 值,在类结构发生改变时(属性增加,删除或者类型修改了)这种也是会导致 serialVersionUID 发生变化。
- 假如类结构没有发生改变,并且没有定义 serialVersionUID ,但是反序列和序列化操作的虚拟机不一样也可能导致计算出来的 serialVersionUID 不一样。
transient
被修饰的字段不进行序列化,重写了writeObjcet\readObject的时候可以将字段进行序列化。(类似钩子方法)
public class User{
private String name;
private transient int age;
private void wirteObject(ObjectOutputStream out){
out.defaultWriteObjcet();
out.writeInt(age);
}
private void readObject(ObjcetInputStream in) {
in.defaultReadObjcet();
age = in.readInt();
}
}
分布式架构下的序列化技术
- XML 序列化框架: XStream 和 Java 自带的 XML
- JSON 序列化框架:序列化效率很快(转化效率和传输效率)
- hessian 序列化框架:性能、易用,比默认的序列化方式更好
- dubbo -> hession2
- Avro 序列化
- kyro 序列化框架
- Protobuf 序列化框架
选型建议
- 对性能要求不高的场景,可以采用基于 XML 的 SOAP 协议
- 对性能和间接性有比较高要求的场景,那么 Hessian、Protobuf、Thrift、Avro 都可以。
- 基于前后端分离,或者独立的对外的 api 服务,选用 JSON 是比较好的,对于调试、可读
性都很不错 - Avro 设计理念偏于动态类型语言,那么这类的场景使用 Avro 是可以的