Java流笔记之对象序列化

java.io.Serializable

java.io.Externalizable

序列化机制可以将实现序列化的对象转换成字节序列,使得对象能脱离java程序存在.如果要使一个对象是可序列化的,需要实现Serializable接口或者Externalizable接口之一.

使用Serializable标记接口实现对象的序列化很简单,只需要目标对象类实现Serializable接口即可,无需实现其方法.如果希望让对象的一些实例变量不被序列化,可以使用transient修饰符修饰.

1.将student对象序列化并储存在磁盘中并读取还原成对象

import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.ClassNotFoundException;

public  class SerializeTest{
	public static void main(String[] args) {
		try(
			ObjectOutputStream oop = new ObjectOutputStream(new FileOutputStream("log.txt"));
			ObjectInputStream oip = new ObjectInputStream(new FileInputStream("log.txt"));
		){
			Student s1 = new Student(3,"李华",1998);
			oop.writeObject(s1);
			Student s = (Student)oip.readObject();
			System.out.println(s.age + "  " + s.name + " " + s.year);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}
class Student implements Serializable{
	int age;
	transient String name;
	int year;
	Student(int age, String name, int year){
		this.age = age;
		this.name = name;
		this.year = year;
	}
}
运行结果:(name用transient修饰,并未被序列化写入到磁盘)
3  null 1998
[Finished in 0.9s]

使用transient修饰的实例成员会被排除在序列化机制外,导致在反序列化时无法获得该实例成员的值.除了transient修饰符之外,Java还提供了自定义序列化机制,通过自动序列化机制,可以使程序自定义控制序列化流程.自定义序列化包含三个方法:

private void writeObject(ObjectOutputStream out) //负责写入对象 默认会调用out.defaultWriteObject()方法
private void readObject(ObjectInputStream in) //负责读取恢复对象 默认会调用in.defaultReadObject()方法
private void readObjectNoDate() //当序列流不完整时,负责初始化反序列化对象

 **注意**

  1. 如果使用序列化向一个文件写入了多个对象,那么读取时是按照写入顺序读取.
  2. 若可序列化对象拥有多个父类,那么这些父类要么有无参的构造器,要么也是序列化的,否则就会抛出InvalidClassException异常.另外,如果父类是不可序列化但有无参数的构造器,则父类中定义的成员变量值不会序列化到二进制流中.
  3. 若类的成员变量不是基本类型或者String,而是其他的引用类型,则这个引用类型也要是可序列化,否则该类无法序列化.(因为在序列化对象时,对象的所有成员变量也会被序列化).
  4. JAVA序列化机制采用了特殊的算法
    • 所有保存到磁盘的对象拥有一个特殊的序列化编号
    • 在程序进行序列化对象之前会检查该对象是否被序列化过,只有在该对象在(本次java虚拟机)未被序列化过时才会将该对象转换成字节系列.
    • 若该对象已经被序列化过,则程序会直接输出该对象的序列化编号.
    • **注意**在对可变对象进行序列化时一定要注意,如果在序列化可变对象后再改变该对象并且进行序列化,程序只会输出该对象改变前的序列化编号,并不会将改变过的对象重新序列化输出.