一、理解
Serializable接口是启用其序列化功能的接口。实现java.io.Serializable 接口的类是可序列化的。没有实现此接口的类将不能使它们的任意状态被序列化或逆序列化。
序列化:把对象转化为字节序列的过程称之为对象的序列化
反序列化:反之,称之为反序列化
Java Serialize序列化机制缺点:
-
序列化数据结果比较大、传输效率比较低
-
不能跨语言对接
Java Serialize序列化机制优点:
1 . 恰当的序列化协议不仅可以提高系统的通用性、强壮型、安全性、优化性能。同时还能让系统更加易于调试和扩展。
历史的选择:Xml ->JSON->二进制:
以至于在后来的很长一段时间,基于XML格式编码的对象序列化机制成为了主流,一方面解决了多语言兼容问题,另一方面比二进制的序列化方式更容易理解。以至于基于XML的SOAP协议及对应的WebService框架在很长一段时间内成为各个主流开发语言的必备的技术。
再到后来,基于JSON的简单文本格式编码的HTTP REST接口又基本上取代了复杂的Web Service接口,成为分布式架构中远程通信的首要选择。但是JSON序列化存储占用的空间大、性能低等问题,同时移动客户端应用需要更高效的传输数据来提升用户体验。在这种情况下与语言无关并且搞笑的二进制编码协议就成为了大家追求的热点技术之一。首先诞生的一个开源的二进制序列化框架-MessagePack。它比google的Protocol Buffers出现得还要早。
二、如何使用,注意事项
如何去实现序列化接口:
- 实现Serializable接口 (implements Serializable)
- 定义 serialVersionUID: 保证可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法或者属性可以用。
- ObjectOutputStream :表示把对象序列化成字节。
- ObjectInputStream : 表示读取指定的字节数据转换成对象。
代码案例:
package com.gupao.vip.serialize.demo1;
/**
* Description:
* User: zhurong
* Date: 2018-08-12 21:42
*/
public class User {
public int userId = 1000;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
'}';
}
}
package com.gupao.vip.serialize.demo1;
import java.io.Serializable;
/**
* Description:
* User: zhurong
* Date: 2018-08-12 13:55
*/
public class Person extends User implements Serializable{
private static final long serialVersionUID = -1253674415533427994L;
private String name;
private static int age;
private transient String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age + '\'' +
", userId=" + userId +
",address="+ address +
'}';
}
}
package com.gupao.vip.serialize.demo1;
import java.io.*;
/**
* 序列化和反序列化
* Description:
* User: zhurong
* Date: 2018-08-12 13:52
*/
public class SerializeDemo {
public static void main(String[] args) throws IOException {
ServializePerson();
DeServializePerson();
}
public static void ServializePerson() throws IOException {
ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File("person")));
Person person = new Person();
person.setAge(32);
person.setName("zhagnsan");
person.setUserId(9999);//父类
oo.writeObject(person);
person.setAge(20);
// person.setUserId(9999);
person.setName("lisi");
oo.close();
}
public static void DeServializePerson() throws IOException {
ObjectInputStream oo = new ObjectInputStream(new FileInputStream(new File("person")));
Person person = null;
try {
person = (Person) oo.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(person.toString());
oo.close();
}
}
总结:
1、在java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化
2、通过ObjectOutputStream和ObjectInputStream对对象进行序列化合反序列化操作
3、对象是否允许被反序列化,不仅仅是取决于对象的代码是否一致,同时还有一个重要的因素(UID)
4、序列化并不保存静态变量的状态,如果已经序列化到一个文本里,如果再去改变该对象中的静态属性,那么反序列化之后这个静态的值是改变值之后的值。
5、要想父类对象也参与序列化操作,那么必须要让父类也实现Serializable接口
6、Transient关键字,主要是控制变量是否能够被序列化。如果没有被序列化的成员变量反序列化后,会被设置成初始值,比如String -> null
7、通过序列化操作实现深度克隆。
8、对同一个对象进行多次写入,打印出的第一次存储结果和第二次存储结果,只多了5(eg)个字节的引用关系。
并不会导致文件累加