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虚拟机)未被序列化过时才会将该对象转换成字节系列.
- 若该对象已经被序列化过,则程序会直接输出该对象的序列化编号.
- **注意**在对可变对象进行序列化时一定要注意,如果在序列化可变对象后再改变该对象并且进行序列化,程序只会输出该对象改变前的序列化编号,并不会将改变过的对象重新序列化输出.
