序列化与反序列化
概述
序列化
把对象以流的方式写到文件中保存,叫写对象的序列化
对象中包含的不仅仅是字符,还有字节
ObjectOutputStram:对象序列化流
反序列化
把文件中保存的对象以流的方式读取出来,叫做读对象,也叫反序列化
读取的文件保存的都是字节流
ObjectInputStream:对象的反序列化流
ObjectOutputStream
构造方法
protected ObjectOutputStream(); :为了完全实现ObjectOutputStream的子类提供一种方法,让它不必分配仅由ObjectOuputStream的实现使用的私有数据.
ObjectOutputStream(OutputStream); :创建写入指定的OutputStream的OutputStream
Serializable接口也叫标记型接口,要进行序列化和反序列化的类必须实现serializable接口,就会给类添加一个标记,当我们进行序列化和反序列化的时候会检测类上是否有这个标记,有就可以序列化和反序列化,没有就会跑出异常
Pserson类
import java.io.Serializable;
//实现这个接口,才能够进行序列化和反序列化
//不然会抛出java.io.NotSerializableException
public class Person implements Serializable {
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
main.java
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
//创建ObjectOutputStream对象,构造方法中传递字节输出流
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(".\\person.txt"));
//使用ObjectOutputStreeam对象中的方法writeObject把对象写入到文件中
oos.writeObject(new Person("姓名",18));
oos.close();
}
}
ObjectInputStream
构造方法
protected ObjectInputStream(); :为完全重新实现ObjectInputStream的子类提供一种方式,让它不必分配仅由ObjectInputStream的实现使用的私有数据
ObjectInputStream(InputStream in); :创建从指定的InputStream读取的ObjectInputStream
反序列化必须要存在对应的class文件
Main.java
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建ObjectInputStream对象,构造方法中传递字节输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(".\\person.txt"));
//使用ObjectInputStream对象中的方法readObject读取保存对象的文件
// readObject还抛出了ClassNotFoundException异常,当不存在class文件的时候会抛出异常
Object o=ois.readObject();///可以强转
//释放资源
ois.close();
//打印对象
System.out.println(o);//Person{name='姓名', age=18}
}
}
transient
static关键字
静态优先于费静态加载到内存中
当jvm吧字节码加载到虚拟机当中,static他修饰的成员会自动的加载到内存当中(方法区),static优先于对象的存在,并且被所有的对象共享
transient
瞬态关键字
如果给了成员变量加上这个这个关键字,就不会参与序列化和反序列化
InvalidClassException
当jvm饭序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么操作也会失败,抛出一个InvaildClassExption异常原因如下
- 该类的序列版本号从流中读取的类描述的版本号不匹配
- 该类包含为止数据类型
- 该类没有可访问的无参构造方法
编译器,会把Person.java文件编译成Person.class文件.PErson类实现了Serializable接口,就会根据类的定义给Person.class文件添加一个序列号
serialversionUID
当修改了类的定义,name就会给Person.class文件重新生成一个新的序列号
反序列化的时候,会使用Person.class文件中的序列号和Person.txt文件中的序列化号进行比较,如果是一样的则反序列化成功,如果不也一样则抛出序列化冲突异常InvaildClassException
问题:每次修改类的定义,都会给class文件生成一个新的编号
解决方案:无论是否对类的定义进行修改,都不重新生成序列号,可以手动各给类添加一个序列号
static final long serialversionUID=42L;