简介
序列化是做什么用的?
序列化(Serialize):将在内存中的对象变为了指定格式的二进制数据。目的是将对象保存在磁盘中,或者允许在网络中直接传输对象。
序列化与反序列化
对象的序列化(Serialize)指将一个 Java 对象写入 IO 流中,与此对应的是,对象的反序列化(Deserialize)则是指的是从 IO 流中恢复该 Java 对象。序列化与反序列化需要用到的类如下:
- 序列化类:
java.io.ObjectOutputStream
将对象变为了指定格式的二进制数据; - 反序列化类:
java.io.ObjectInputStream
可以将序列化的对象转换回对象内容;
实现序列化操作类:ObjectOutputStream
- 构造方法:public ObjectOutputStream(OutputStream out) throws Exception
- 输出对象:public final writeObject(Object obj) throws Exception;
如何序列化?
如果要序列化对象,那么其所在的类一定要实现 java.io.Serializable
接口。但是这个接口里面没有任何的操作方法存在,因为它是一个标识接口。
代码实例
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
//如果不想加上序列化的那段代码,可以使用注解: @SuppressWarnings("serial") // 实现序列化接口
class Book implements Serializable {
// 由于序列化需要给类一个指定的序列化编码,所以需要加上这端代码
private static final long serialVersionUID = 729234114635241116L;
private String tiltle;
private double price;
public Book(String title, double price) {
this.tiltle = title;
this.price = price;
}
@Override
public String toString() {
return "书名《" + this.tiltle + "》,价格:" + this.price + "元。";
}
}
public class Test {
// 序列化
public static void ser() throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(new File("e:" + File.separator + "book.ser")));
oos.writeObject(new Book("Java从入门到精通", 88.8));
oos.close(); // 关闭流
}
// 反序列化
public static void dser() throws Exception {
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(new File("e:" + File.separator + "book.ser")));
Object obj = ois.readObject();
Book book = (Book) obj;
System.out.println(book);
ois.close(); // 关闭流
}
public static void main(String[] args) throws Exception {
ser(); // 序列化
// dser(); // 反序列
}
}
序列化结果:
反序列结果:
书名《Java从入门到精通》,价格:88.8元。
transient 关键字
序列化操作时,是将整个对象所有的属性内容进行了保存,现在有些属性的内容不需要被保存,就可以通过 transient 关键字来定义。定义如下:
private transient String title;
如果通过 transient 关键字修改了 title 属性,那么执行序列化之后,再执行反序列化的时候,就获取不到之前设置进去的值了。
注
当程序序列化一个 Teacher 对象时,如果该 Teacher 类对象持有一个 Person 类对象的引用,为了在反序列化是可以正常恢复该 Teacher 类对象,程序就会顺带将该 Person 对象也进行序列化,所以 Person 类也必须要是可以序列化的。
Java 序列化机制采用了一种特殊序列化算法,其算法内容如下:
- 所有保存到磁盘中的对象都有一个序列化编号
- 当程序视图序列化一个对象时,程序将先检查该对象是否已经序列化过,只有改对象从未被序列化(在本次的虚拟机中序列化),系统才会将该对象转换成字节序列并输出
- 如果某个对象已经序列化过了,程序只是直接输出一个序列化编号,而不是再次重新序列化改对象。
多次序列化同一个对象
由于 Java 序列化机制使然,如果多次序列化同一个 Java 对象,只有第一次序列化时才会把该 Java 对象转换成直接序列并输出,这样可能引起一个潜在的问题:
当程序序列化一个可变对象时,只有第一次使用 writeObject() 方法输出时,才会将该对象转换成字节序列并输出,当程序再次调用 writeObject() 方法时,程序只是输出前面的序列化编号,及时后面改对象的实例值已经被改变,改变的实例变量值也不会被输出。