Granda's Blog

JAVA:对象序列化

序列化的定义

  • 序列化机制允许将Java对象转换成字节序列,存于磁盘中,或者用于网络传输,以便以后恢复成原来的Java对象
  • 序列化:将一个Java对象写入IO流中
  • 反序列化:从IO流中恢复出Java对象
  • 序列化需要实现两个接口之一:Serializable,Externalizable

序列化实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Person implements java.io.Serializable{
private String name;
private int age;
public Person(String name,Int age){
this.name = name;
this.age = age;
}
}
public class WriteObject{
public static void main(String[] args){
try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("out.txt"))){
Person per = new Person("Joe",20);
//将要序列化的Person实例写入输出流
oos.writeObject(per);
}catch(IOException e){
e.printStackTrace();
}
}
}

序列化需要注意的地方

  • 对象的类名、实例变量会被序列化;而方法、类变量、transient实例变量(瞬态变量)是不会被序列化的
  • 反序列化读取的仅仅是对象的数据,因此反序列化时必须要有反序列化对象的class文件
  • 当一个可序列化类有多个父类时,这些父类要么有无参构造,要么也是可以序列化的,否则抛出InvalidClassException
  • 所有序列化保存到磁盘的对象都有一个序列化编号
  • 如果一个对象已经序列化过,程序将只是输出一个序列化编号,而不是再次序列化该对象

自定义序列化

  • 被transient修饰的实例变量将不会被序列化
  • 实现Serializable接口的序列化类,可以重写以下两个方法实现自定义序列化

    1
    2
    private void writeObject(java.io.ObjectOutputStream out) throws IOException
    private void readObject(java.io.ObjectInputStream in)throws IOException,ClassNotFoundException
  • 如果需要序列化某个对象时替换改对象,提供如下方法

    1
    ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
  • 在序列化对象时,先执行writeReplace() 方法,返回对象后,继续执行返回对象的writeReplace方法,直至该方法不返回另外一个对象为止,最后调用writeObject()方法保存该对象

  • 如果序列化类实现Externalize接口,必须实现下面两个方法

    1
    2
    void readExternal(ObjectInput in)
    void writeExternal(ObjectOutput out)
  • 当使用Externalizable机制反序列化对象时,会先使用public的无参构造器创建实例,然后才执行readExternal()方法进行反序列化,故实现Externalizable的序列化类必须有public的无参构造器

实现Serializable接口 实现Externalizable接口
系统自动存储必要的信息(也可以手动改写) 程序员决定存储哪些信息
Java内建支持,易于实现,只需要实现接口,不需要代码支持 仅仅提供两个空方法,实现接口必须实现该方法
性能略差 性能略好

序列化版本号

  • 为序列化类显式提供版本号

    1
    private static final long serialVersionUID = 222L ;
  • 版本号不同将会导致序列化失败

  • 下面几种情况,同版本号的类反序列化不受影响:
  1. 修改类时只修改了方法
  2. 修改类时只修改了类变量和瞬态变量
  3. 对象流中含有更多或更少于新类中的实例变量,多时忽略,少时赋0和null·