疯狂Java学习笔记(56)------------对象序列化
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接口
[java] view plain copy <span style="font-size:18px;">import java.io.Serializable; /** * <p>ClassName: Person<p> * <p>Description:测试对象序列化和反序列化<p> * @author xudp * @version 1.0 V * @createTime 2014-6-9 下午02:33:25 */ public class Person implements Serializable { /** * 序列化ID */ 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; /** * <p>ClassName: TestObjSerializeAndDeserialize<p> * <p>Description: 测试对象的序列化和反序列<p> * @author xudp * @version 1.0 V * @createTime 2014-6-9 下午03:17:25 */ 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())); } /** * MethodName: SerializePerson * Description: 序列化Person对象 * @author xudp * @throws FileNotFoundException * @throws IOException */ 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(); } /** * MethodName: DeserializePerson * Description: 反序列Perons对象 * @author xudp * @return * @throws Exception * @throws IOException */ 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来持久化对象,在该类中有如下代码: