1. 什么是序列化 和 反序列化
序列化:把对象转换为字节序列的过程称为对象的序列化。将内存中的对象按照指定的格式输出到输出设备上。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
为什么要有文件的 序列化和反序列化?
有时候我们想把一些信息持久化保存起来,那么序列化的意思就是把内存里面的这些对象给变成一连串的字节描述的过程。 常见的就是变成文件。但是有的属性为了安全起见,并不需要保存到文件中,例如密码,年龄,身份证号等等涉及个人隐私的,需要有关键字修饰,将变量不再是对象持久化的一部分。
2. 什么时候需要序列化
- 把内存中的对象状态保存到一个文件中 或者 一个数据库 中。
- 用套接字在网络上传送对象的时候。
3. 如何实现序列化
package sin_2020_03_01.Serialize;
import java.io.*;
public class TestDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
serializePerson();
Person person = deserializePerson();
System.out.println(person);
}
// 反序列化
private static Person deserializePerson() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\test\\IO流\\person.txt"));
Person person = (Person)ois.readObject();
System.out.println("person 反序列化成功");
return person;
}
// 序列化
private static void serializePerson() throws IOException {
Person person = new Person();
person.setName("xixi");
person.setAge(18);
person.setSex("女");
person.setStuId(100);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\test\\IO流\\person.txt"));
oos.writeObject(person);
System.out.println("person 对象序列化成功");
oos.close();
}
}
class Person implements Serializable {
private String name;
private int age;
private String sex;
// transient 修饰的变量不能被序列化
transient private int stuId;
// static 修饰的变量,不能被序列化
private static int count = 99;
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;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getStuId() {
return stuId;
}
public void setStuId(int stuId) {
this.stuId = stuId;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", stuId=" + stuId +
", count=" + count+
'}';
}
}
序列化/反序列化 | 序列化 | 反序列化 |
---|---|---|
流的方向 | 输出 | 输入 |
选择的流 | ObjectOutputStream | ObjectInputStream |
构造方法 | ObjectOutputStream(new FileInputStream(File file)) | ObjectInputStream(new FileInputStream(File file)) |
调用的方法 | oos.writeObject(oerson) | (Person)ois.readObject() |
4. 关于静态数据是否被序列化的测试
在上述例子中,其他代码不变,进行 1)将类中静态变量count 的值设置为 777,2)主函数的调用改为如下形式:
public static void main(String[] args) throws IOException, ClassNotFoundException {
//serializePerson();
Person person = deserializePerson();
System.out.println(person);
}
运行结果为
5. 关于serialVersionUID的问题
将上述代码再执行一遍运行(序列化和反序列化均要执行),1)将Person类中的 private static
final long serialVersionUID = 1L; 注释取消,2)然后屏蔽掉序列化的方法:serializePerson() ,3)运行主函数。
目的:当我们在类中没有指定 serialVersionUID 的时候,编译器会自动赋值,如果序列化是以默认
的 serialVersionUID ,那么反序列化也是会以那个默认的。而我们现在的情况是,以默认的
serialVersionUID 进行序列化,以自己赋值的 serialVersionUID 进行反序列化,这样代码就会出问
题。
6. 总结
- 一个类如果想被序列化,那么需要实现一个Serializable接口;
- 类中的静态变量的值是不会被进行序列化的;
- transient 修饰的属性,是不会被序列化的,内置类型为对应0值。引用类型为null;
- 在实现这个Serializable 接口的时候,一定要给这个 serialVersionUID 赋值,最好设置为1L,这
个L最好大写来区分,不然小写看起来像是1,不同的 serialVersionUID 的值,会影响到反序列化