Java 对象序列化与反序列化

摘要:本文是关于Java对象序列化与反序列化知识的一个总结和概括,Java对象序列化与反序列提供了一种数据持久化的方式,掌握Java对象序列化与反序列对Java基础知识以及以后的框架学习都有很大的帮助。

序列化与反序列化引言

我们在程序创建的Java对象都是存在于JVM内存中的,也就是Java对象的生命周期一定不会长于JVM,所以如何以一种持久化的方式保留用户创建的对象呢,这就需要用到对象序列化的知识,将序列化的对象重新还原称为Java对象,即为反序列化。

关于Java对象序列化与反序列化,我们需要理解的一点是,序列化只是将Java对象以一种二进制数据流的方式保存到本地文件或其他介质中,它实际上保存的只是实例化对象的一种状态,对于静态成员,是无法序列化保存的

序列化与反序列化方法

Java对象要支持序列化,该类必须要具有可序列化的特性,真正提供实现序列化与反序列化方式的ObjectInputStream和ObjectOutputStream类。Java对象序列化的方式可以分为普通方式和定制方式两种,普通方式,借助Serializable接口完成,不需要用户做过多的干涉和修改;定制方式,用户可以使用transient关键字修饰类中某个属性,使该属性屏蔽序列化特性,使用transient关键字屏蔽之后,被transient修饰的字段序列化后取默认值,而非序列化之前的实例化对象值。如果需要序列化该字段,我们可以将transient关键字去掉,也可以在该类中重写readObject和writeObject方法,并在重写方法中继续序列化屏蔽的字段,从而达到反屏蔽的效果。除了使用transient关键字,重写readObject和writeObject方法实现定制序列化的方式,还有一种与Serializable方式完全不同的支持定制序列化的方式,是指定该类继承自Externalizable接口,但是继承自该接口的类必须明确重写readExternal和writeExternal方法才能实现对象序列化与反序列化,在这两个方法里指定需要序列化和反序列化的属性字段,没有指明的属性将不会被序列化。

程序示例

import java.io.*;
public class TestObjSer{
 	public static void main(String[] args) throws Exception{
  		String stuFilePath = "./student.out";
  		String codFilePath = "./coder.out";
  		File file = new File(codFilePath);
  		if(!file.exists()){
   			System.out.println("The serialization file does not exist, which will be created right now!");
   			file.createNewFile();
  		}
     	Student stu = new Student("zhangsan", 17, Gender.MALE, "CSU");
     	Coder coder = new Coder("lisi", 18, Gender.FEMALE, "JAVA");
        FileInputStream fis = new FileInputStream(file);
       	FileOutputStream fos = new FileOutputStream(file);
  
       	//following two stream can not be disordered, I have no idea why is this
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        ObjectInputStream ois = new ObjectInputStream(fis);
        serObj(oos,coder);
        deSerObj(ois);
 	}
 
 	public static void serObj(ObjectOutputStream oos,Object obj) throws Exception {
  		oos.writeObject(obj);
  		oos.close();
 	}
 
 	public static void deSerObj(ObjectInputStream ois) throws Exception {
  		Person per = (Person)ois.readObject();
  		ois.close();
 		System.out.println(per);
 	}
}
 
/**
 * the enum type is a special type in Java, which is generated from 
 * class Enum by default and class Enum implements the interface Seralizable
 * so it can be serialized and all member of enum should be capital
 */
enum Gender{
 	MALE,FEMALE
}

/**
 * superclass should implement Serialzable
 */
class Person implements Serializable{
 	private String name;
 	private int age;
 	private Gender gender;
 	public Person(){
  		System.out.println("Non-Arg constructor be called!");
 	}

 	public Person(String name, int age, Gender gender){
  		System.out.println("Arg constructor be called!");
  		this.name = name;
  		this.age = age;
  		this.gender = gender;
 	}

	public String getName() {
     	return this.name;
 	}

 	public int getAge() {
     	return this.age;
 	}

 	public Gender getGender(){
  		return this.gender;
 	}

	public void setName(String name) {
     	this.name = name;
 	}

 	public void setAge(int age) {
     	this.age = age;
 	}

 	public void setGender(Gender gender){
  		this.gender = gender;
	}

 	public String toString(){
  		return "Per(name = " + this.getName() + ", age = " 
  		+ this.getAge() + ", gender = " + this.getGender() +")";
 	}
}

class Student extends Person{
 	//use transient to avoid the field school be serialized
 	private transient String school;
 	public Student(){
  		super();
 	}

 	public Student(String name, int age, Gender gender, String school){
  		super(name, age, gender);
  		this.school = school;
 	}

	public String getSchool() {
	    return this.school;
	}

 	public void setSchool(String school) {
     	this.school = school;
 	}

 	public String toString(){
  		return "Stu(name = " + this.getName() + ", age = " + this.getAge() + 
  		", gender = " + this.getGender() + ", school = " + this.getSchool() +")";
 	}

 	private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();//call super
        oos.writeObject(school);
    }

    private void readObject(ObjectInputStream ois) throws Exception{
        ois.defaultReadObject();//call super
        this.school = (String)ois.readObject();
    }
}

class Coder extends Person implements Externalizable {
 	private String language;
 		public Coder(){
  		super();
 	}

 	public Coder(String name, int age, Gender gender, String language){
  		super(name, age, gender);
  		this.language = language;
	}

 	public String getLanguage() {
     	return this.language;
 	}

 	public void setLanguage(String language) {
     	this.language = language;
 	}

 	public String toString(){
  		return "Cod(name = " + this.getName() + ", age = " + this.getAge() + 
  		", gender = " + this.getGender() + ", language = " + this.getLanguage() +")";
 	}
	/**
	  * [readExternal description]serialize by this method should 
	  * specify field in readExternal and writeExternal method by user,
	  * it is completely different from Serialzable
	  * @param  in                     [description]
	  * @throws IOException            [description]
	  * @throws ClassNotFoundException [description]
	 */
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
     	this.setName((String)in.readObject());
     	this.setAge(in.readInt());
     	this.setGender((Gender)in.readObject());
     	this.language = (String)in.readObject();
    }
    
    public void writeExternal(ObjectOutput out) throws IOException {
     	out.writeObject(this.getName());
     	out.writeInt(this.getAge());
     	out.writeObject(this.getGender());
     	out.writeObject(this.language);
    }
}

序列化与反序列化总结

上面的程序示例基本展示了Java对象序列化与反序列化的所有知识,还有一些相关知识,希望在这里啰嗦几句: