Crazy Java study notes (56)------------Object serialization
1. The state of the object needs to be saved to a file (storage), and then the object can be reconstructed by reading the object state to restore the program state
2. It is very useful for programs that use sockets to transfer objects over the network (transmission).
We can serialize a class by having it implement the java.io.Serializable interface. This interface is a marker interface. That is, the interface does not need to implement any methods for the class to implement it. It is mainly used to notify the Java Virtual Machine (JVM) that an object needs to be serialized.
There are a few things we need to be clear about this:
1. Not all classes can be serialized. Under cmd, we enter serialver java.net.socket to get information about whether the socket can be serialized. In fact, the socket is not serializable.
2. There are many basic classes in java that have implemented the serializable interface, such as string, vector, etc. But for example hashtable does not implement the serializable interface.
There are two main classes for reading or writing objects to streams: ObjectOutputStream and ObjectInputStream.
java.io.ObjectOutputStream represents the object output stream, and its writeObject(Object obj) method can serialize the obj object specified by the parameter, and write the obtained byte sequence to a target output stream.
java.io.ObjectInputStream represents an object input stream, and its readObject() method reads byte sequences from a source input stream, deserializes them into an object, and returns it.
Only objects of classes that implement the Serializable and Externalizable interfaces can be serialized. The Externalizable interface inherits from the Serializable interface. The class that implements the Externalizable interface completely controls the serialization behavior by itself, while the class that only implements the Serializable interface can use the default serialization method.
对象序列化包括如下步骤:
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来持久化对象,在该类中有如下代码: