1.需要将对象的状态保存到文件中(存储),而后能够通过读入对象状态来重新构造对象,恢复程序状态
2.使用套接字在网络上传送对象的程序来说,是很有用的(传输)。
我们通过让类实现java.io.Serializable 接口可以将类序列化。这个接口是一个制造者(marker)接口。也就是说,对于要实现它的类来说,该接口不需要实现任何方法。它主要用来通知Java虚拟机(JVM),需要将一个对象序列化。
对于这个,有几点我们需要明确:
1.并非所有类都可以序列化,在cmd下,我们输入serialver java.net.socket,可以得到socket是否可序列化的信息,实际上socket是不可序列化的。
2.java有很多基础类已经实现了serializable接口,比如string,vector等。但是比如hashtable就没有实现serializable接口。
将对象读出或者写入流的主要类有两个: ObjectOutputStream与ObjectInputStream 。
java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。
对象序列化包括如下步骤:
1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
2) 通过对象输出流的writeObject()方法写对象。
对象反序列化的步骤如下:
1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
2) 通过对象输入流的readObject()方法读取对象。
对象序列化和反序列范例:
定义一个Person类,实现Serializable接口
- <span style="font-size:18px;">import java.io.Serializable;
- public class Person implements Serializable {
- private static final long serialVersionUID = -5809782578272943999L;
- private int age;
- private String name;
- private String sex;
- public int getAge() {
- return age;
- }
- public String getName() {
- return name;
- }
- public String getSex() {
- return sex;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public void setName(String name) {
- this.name = name;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- }</span>
序列化和反序列化Person类对象
- <span style="font-size:18px;">import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- import java.text.MessageFormat;
- public class TestObjSerializeAndDeserialize {
- public static void main(String[] args) throws Exception {
- SerializePerson();//序列化Person对象
- Person p = DeserializePerson();//反序列Perons对象
- System.out.println(MessageFormat.format("name={0},age={1},sex={2}",
- p.getName(), p.getAge(), p.getSex()));
- }
- private static void SerializePerson() throws FileNotFoundException,
- IOException {
- Person person = new Person();
- person.setName("gacl");
- person.setAge(25);
- person.setSex("男");
- // ObjectOutputStream 对象输出流,将Person对象存储到E盘的Person.txt文件中,完成对Person对象的序列化操作
- ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(
- new File("E:/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("E:/Person.txt")));
- Person person = (Person) ois.readObject();
- System.out.println("Person对象反序列化成功!");
- return person;
- }
- }</span>
serialVersionUID的作用
简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)
举个实际应用的例子:
为了实现系统交互的目的,我们需要系统之间通过网络传输对象的实体(这些对象一般都是包括了系统中的一些数据)
Java序列化是一种解决方案:
系统A和B之间要进行交互,则A中的对象a首先会序列化,然后通过网络传输到系统B,在B中经反序列化还原,然后对其进行操作,利用对象a所提供的数据。
但要实现这种方案对原来的系统有如下的要求:
交互的系统之间要存在完全一致的对象模型,这就需要对原来的系统进行比较大的改变,不符合我们的要求。
因为序列化传输的数据是二进制格式的,除非把这些二进制的数据反序列化为对象,否则我们根本不能对其数据进行处理,也不能看到里面包含的数据是什么。
要求交互的系统都是基于Java的,因为Java序列化只能应用与Java系统之中。
Serializable的作用
为什么一个类实现了Serializable接口,它就可以被序列化呢?在上节的示例中,使用ObjectOutputStream来持久化对象,在该类中有如下代码:
良心的公众号,更多精品文章,不要忘记关注哈
《Android和Java技术栈》