Java对象序列化和反序列化
在Java中,我们如果要保存一个对象的瞬时状态值,以便在下次使用时能够得到这些值,或者持久化对象,或者使用RMI(远程方法调用),或在网络中传递对象时,此时我们就需要将对象序列化,实现序列化,我们只要实现Serializable接口,该接口是一个标记接口(Tag interface),即里面没有方法,其主要作用就是告诉JVM该类的对象可以进行序列化。
一般来说,很多类的对象都实现了Serializable接口,但是,有些对象是不能进行序列化的,比如与数据库相关的连接对象,file对象等等,保存这些对象的状态值是没有意义的,因此Object并没有实现Serializable接口也是这个原因,若想要将对象序列化,我们只要实现Serializable接口即可,一个类的父类实现了Serializable接口,则其子类默认也会实现该接口,反过来,若其子类需要序列化,则其父类必须要实现Serializable接口。
序列化是为了保存对象的状态,因此,static类型的变量不会被序列化,因为保存其值是没有意义的,它会在运行过程中动态变化的,对于引用类型的变量,或者其引用变量中又包含引用变量,我们在序列化该对象时,都对其进行了序列化,我们只要确保他们都实现了Serializable接口。
在序列化的过程中,如果对于有些变量,我们不希望保存其值,那么我们在该引用变量或者原始变量名前加上关键字transient即可,这样,该字段就不会被序列化了,在反序列化恢复成对象时,其默认值为null(字段为对象类型)或者原始类型的默认值(原始类型变量)。
在反序列化时,JVM将序列化的对象进行重新组装,然后在heap中开辟空间,生成相应类型的对象,在该过程中,其并不调用构造器。当然,我们我们如果不想使用java提供的默认的序列化方式,我们只要实现Externalizable接口即可,当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。用该接口时,序列化的细节需要由程序员去完成。
举例如下:
package com.test;
import java.io.Serializable;
/**
* Created by siege on 2015-07-28.
*/
public class Person implements Serializable {
private transient int num=3;
private transient String description="hello";
private static int count;
private String name;
private int age;
public Person(String name, int age) {
count++;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "name"+":"+name+",age:"+age+",count:"+count+",num:"+num+",description:"+description;
}
}
package com.test;
import java.io.*;
/**
* Created by siege on 2015-07-28.
*/
public class SerializableTest {
public static void main(String[] args) {
Person person1=new Person("siege1",20);
Person person2=new Person("siege2",21);
Person person3=new Person("siege3",22);
try {
FileOutputStream fos=new FileOutputStream("C:\\test\\person.out");
ObjectOutputStream objectOutputStream=new ObjectOutputStream(fos);
objectOutputStream.writeObject(person1);
objectOutputStream.writeObject(person2);
objectOutputStream.writeObject(person3);
objectOutputStream.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
try {
FileInputStream fin=new FileInputStream("C:\\test\\person.out");
ObjectInputStream objectInputStream=new ObjectInputStream(fin);
try {
Person p1=(Person)objectInputStream.readObject();
Person p2=(Person)objectInputStream.readObject();
Person p3=(Person)objectInputStream.readObject();
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出结果如下:
name:siege1,age:20,count:3,num:0,description:null
name:siege2,age:21,count:3,num:0,description:null
name:siege3,age:22,count:3,num:0,description:null
由此可见,static变量的值是在我们反序列化之后再从类变量中取出放入对象中的,同时,transient类型的变量没有序列化,反序列化的值为默认值。
若Person没有实现Serializable接口,则会出现
java.io.NotSerializableException
错误。
版权声明:本文为博主原创文章,未经博主允许不得转载。