概念
序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
目的
① 方便进行数据传输。在分布式系统中,需要把对象在网络上传输,所以需要把对象数据转换为二进制形式。
② 节省服务器内存。如果服务器发现某些对象好久没有活动了,那么服务器就会把这些内存中的对象持久化在本地磁盘文件中(Java对象转换为二进制文件);如果服务器发现某些对象需要活动时,先去内存中寻找,找不到再去磁盘文件中反序列化对象数据,将其恢复为Java对象。
实现
① 实现Serializable或者Externalizable接口。Externalizable接口继承自Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serialzable接口的类可以采用默认的序列化方式。
② 对象序列化
(1) 创建一个对象输出流ObjectOutputStream,它可以包装一个其他类型的目标输出流,如文件输出流。
(2) 通过对象输出流的writeObject()方法写对象。
③ 对象反序列化
(1) 创建一个对象输入流ObjectInputStream,它可以包装一个其他类型的源输入流,如文件输入流。
(2) 通过对象输入流的readObject()方法读取对象。
例子
① 建立一个JavaBean用于序列化和反序列化
/** * 定义一个Person类,实现Serializable接口 * @author N.Y * */ public class Person implements Serializable{ /** * 序列化ID */ private static final long serialVersionUID = -5809782572943999L; private int age; private String name; private transient String sex; //transient关键字可以使sex这个变量不能被序列化,拥有static关键词的变量也不可以被序列化和反序列化
//详情可以参考这篇文章:https://blog.csdn.net/qq_27093465/article/details/78544505 public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public static long getSerialversionuid() { return serialVersionUID; } }
② 利用ObjectOutputStream和ObjectInputStream来实现对象的序列化和反序列化
public class TestObjSerializeAndDeserialize { public static void main(String[] args) throws IOException, Exception { SerializePerson(); //序列化Person对象 Person p = DeserializePerson(); //反序列化Person对象 System.out.println(MessageFormat.format("name={0}, age={1}, sex={2}", p.getName(), p.getAge(), p.getSex())); } /** * 序列化Person对象 * @throws FileNotFoundException * @throws IOException */ private static void SerializePerson()throws FileNotFoundException, IOException{ Person person = new Person(); person.setName("Nicole"); person.setAge(19); person.setSex("男"); //ObjectOutputStream对象输出流,将Person对象存储到person.txt文件中,完成对Person对象的序列化 ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File("person.txt"))); oo.writeObject(person); System.out.println("Person对象序列化成功."); oo.close(); } private static Person DeserializePerson() throws Exception,IOException{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("person.txt"))); Person person = (Person)ois.readObject(); System.out.println("Person对象反序列化成功."); return person; } }
serialVersionUID的作用
固定版本,因为serialVersionUID取值是Java运行时环境根据类的内部细节自动生成的,只要class文件稍有改变其生成的serialVersionUID就截然不同了,而且也有可能换了个编译器它的serialVersionUID也会不同;可以根据版本号来进行反序列化。
为了提高serialVersionUID的独立性和确定性,建议在一个可序列化类中显式定义serialVersionUID,为它赋予明确的值。一是为了确保类的不同版本具有相同的serialVersionUID,二是即使在某些场合中不希望类的不同版本对序列化兼容,那显式定义serialVersionUID可以确保类的不同版本具有不同的serialVersionUID。
参考:
https://blog.csdn.net/qq_27093465/article/details/78544505
https://www.cnblogs.com/ysocean/p/6870069.html
https://www.cnblogs.com/xdp-gacl/p/3777987.html