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