1.关于序列化和反序列化
把对象转换为字节序列的过程称为对象的序列化;将字节序列恢复为对象的过程称为反序列化。对象的序列化主要有两种用途:1)持久化,将对象持久化到磁盘上。2)网络传输,在网络上传输对象的字节序列。3)对象的复制,克隆的方法如果要实现多层克隆的话,还是比较麻烦的,序列化可以很方便的进行对象的复制,只要实现相关接口就行。
2.如何实现序列化
java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。注意:为了正确读取数据,完成反序列化,必须保证向对象输出流写对象的顺序与从对象输入流中读对象的顺序一致。
package serial;
import java.io.*;
public class Student implements Serializable {
private String name;
private int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Student(){}
public Student(String name,int age){
this.name = name;
this.age = age;
}
public static void main(String[] args) throws Exception {
Student winterIC = new Student("winterIC", 18);
FileOutputStream fo = new FileOutputStream("test.txt");
ObjectOutputStream out = new ObjectOutputStream(fo);
out.writeObject(winterIC);
FileInputStream fi = new FileInputStream("test.txt");
ObjectInputStream in = new ObjectInputStream(fi);
Student student = (Student)in.readObject();
System.out.println(student);
//记得关闭输入输出流
}
}
3.注意事项:
a)transient关键字修饰的属性不能被序列化,类变量不能被序列化,因为序列化保存的是对象的状态,而不是类变量的状态(通过对象可以访问类变量)。
b)serialVersionUID,类型为Long型。可以理解为类的版本号,当类中不指定的时候,jvm会帮我生成一个,如果序列化的对象类的版本号不一致是无法被序列化的。
c)AC 问题向一个文件中追加对象时,会再次向文件中写一个header,反序列化读取文件流的时候,只会读取一次,如果再次读到文件流,程序就会报错invalid type code:AC
4.解决AC问题
向文件中写数据的时候,先判断一下是否有数据存在,如果有就不写如header,否则则写入。
public static void main(String[] args) throws Exception {
Student winterIC = new Student("winterIC", 19);
File file = new File("test.txt");
FileOutputStream fo = new FileOutputStream(file,true);
ObjectOutputStream out = null;
if (file.length()>0){
out= new MyOutputStream(fo);
}else{
out = new ObjectOutputStream(fo);
}
out.writeObject(winterIC);
FileInputStream fi = new FileInputStream("test.txt");
ObjectInputStream in = new ObjectInputStream(fi);
Student student1 = (Student)in.readObject();
Student student2 = (Student)in.readObject();
System.out.println(student1);
System.out.println(student2);
}
5.解决多层克隆的问题
如果要克隆的类型里面包含了很多引用的类型,clone就会很麻烦。这时可以用序列化的方式来实现对象的复制。前提是所有的引用类型都要实现序列化。
public static void main(String[] args) throws Exception {
Student winterIC = new Student("winterIC", 19);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(winterIC);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream in= new ObjectInputStream(bais);
Student o = (Student)in.readObject();
System.out.println(o==winterIC);
}
6.继承关系的序列化
如果子类没有实现序列化接口,父类实现了序列化接口,由于继承关系,子类也间接实现了序列化接口,这时子类可以被序列化。若父类没有实现序列化接口,而子类实现了序列化接口则子类属性可以被序列化,父类属性不可以被序列化。
public static void main(String[] args) throws Exception {
Student winterIC = new Student("winterIC", 19);
winterIC.abc = "aaa";
winterIC.abc2 = "222";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(winterIC);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream in= new ObjectInputStream(bais);
Student o = (Student)in.readObject();
System.out.println(o.abc);
System.out.println(o.abc2);
}
要想序列化父类的属性首先要保证父类有一个无参构造器,其次手动的序列化父类的属性
class People2 {
public String abc2;
public People2(){}
public People2(String name){
this.abc2 = name;
}
}
public class Student extends People2 implements Serializable {
public String name;
private int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Student(){}
public Student(String name,int age){
this.name = name;
this.age = age;
}
private void writeObject(ObjectOutputStream out) throws Exception{ //这个方法必须是私有的,要不然不会被调用
out.defaultWriteObject();
out.writeObject(abc2);
}
private void readObject(ObjectInputStream in) throws Exception{ //同上
in.defaultReadObject();
abc2 = (String) in.readObject();
}
public static void main(String[] args) throws Exception {
Student winterIC = new Student("winterIC", 19);
winterIC.abc2 = "haha";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(winterIC);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream in= new ObjectInputStream(bais);
Student o = (Student)in.readObject();
System.out.println(o);
System.out.println(o.abc2);
}
}
序列化基础知识点到此完结。