对象序列化
对象序列化的目标是把对象保存到磁盘中,转化为平台无关的二进制流,从而允许吧这种二进制流持久保存在磁盘上,也可以用过网络传输。程序只要得到了这种二进制流,则可以将这种二进制流转换为Java对象。
为了让某个类是可序列化的,必须实现以下两个类中的任意一个:
Serializable
Externalizable
所有可能在网络上传输的对象的类必须是可序列化的:如RMI,所有需要保存到磁盘的对象也是必须可序列化的,如HttpSession,ServletContext属性的对象
Serializable实现对象的序列化
序列化:1.创建ObjectOutPutStream
2.调用该流的writeObject方法,输出序列化对象
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
private int no;
private String name;
public Student(int no, String name) {
super();
this.no = no;
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student [no=" + no + ", name=" + name + "]";
}
}
public class WriteStudent {
public static void main(String[] args) throws IOException {
FileOutputStream outputStream = new FileOutputStream("e://student");
//创建输出流
ObjectOutputStream oos = new ObjectOutputStream(outputStream);
//创建要序列化的对象
Student student = new Student(1, "jack");
//输出序列化对象
oos.writeObject(student);
oos.close();
}
}
上面完成了对象的序列化,在输出流的路径可以看到该序列化对象的二进制文件,
如果要恢复该对象,则需要反序列化该对象:
public class ReadStudent {
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream in = new FileInputStream("e://student");
ObjectInputStream ois = new ObjectInputStream(in);
Student student = (Student) ois.readObject();
System.out.println(student);
ois.close();
}
}
注意:
1.反序列化读取的是java对象的数据,而不是java类,因此反序列化恢复java对象必须提供该类的class文件,否则引发ClassNotFoundException异常
2.反序列化读取java对象不会调用该类的构造器。
3.当可序列化对象有多个父类是,其父类必须也是可序列化或者有无参的构造器的,如果父类有午餐构造器但是不可序列化,则该父类的成员变量的值不会序列到二进制流中。
4.如果某个类的成员变量不是基本类型,则该引用类必须也是可序列化的,否则引用这个类的类也是不可序列化的
对象引用的序列化
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
private int no;
private String name;
private Pet pet;
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
public Student(int no, String name, Pet pet) {
super();
this.no = no;
this.name = name;
this.pet = pet;
}
public Student(int no, String name) {
super();
this.no = no;
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student [no=" + no + ", name=" + name + ", pet=" + pet + "]";
}
}
两个Student类引用到了同一个Pet对象,序列化该两个Student类只会写入三个对象,pet类不会重复序列化两次
public class StudentTest {
public static void main(String[] args) throws IOException {
FileOutputStream outputStream = new FileOutputStream("e://student");
//创建输出流
ObjectOutputStream oos = new ObjectOutputStream(outputStream);
//创建要序列化的对象
Pet pet = new Pet("tom", "yellow");
//成员变量引用了同一个对象
Student student = new Student(1, "jack",pet);
Student student2 = new Student(2, "rose",pet);
//输出序列化对象
oos.writeObject(student);
oos.writeObject(student2);
oos.close();
}
}
比较两个student类中的pet是同一个类
public class ReadStudent {
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream in = new FileInputStream("e://student");
ObjectInputStream ois = new ObjectInputStream(in);
Student student = (Student) ois.readObject();
Student student2 = (Student) ois.readObject();
System.out.println(student);
System.out.println(student2);
System.out.println(student.getPet()==student2.getPet()); //输出true
ois.close();
}
}
java序列化采用的序列化算法:
1.所有保存到磁盘中的对象都有一个序列化编号
2.开始序列化时,判断该对象是否已经被序列化过,如果没有才进行序列化
2.如果序列化过,则只是输出一个序列化编号,不会再次序列化
当序列化一个可变对象时,只有第一次序列化时会转换成字节码输出,以后只会输出一个序列化序号,序列化后修改该对象的实例变量,然后再次序列化,则该实例变量不会改变
public class StudentTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileOutputStream outputStream = new FileOutputStream("e://pet");
FileInputStream inputStream = new FileInputStream("e://pet");
// 创建输出流
try (ObjectOutputStream oos = new ObjectOutputStream(outputStream);
ObjectInputStream ois = new ObjectInputStream(inputStream)) {
// 创建要序列化的对象
Pet pet = new Pet("tom", "yellow");
// 输出序列化对象
oos.writeObject(pet);
// 修改对象的实例变量的值
pet.setColor("red");
oos.writeObject(pet);
Pet p = (Pet) ois.readObject();
System.out.println(p); // color=yellow 不会变为red
}
}
}