什么是序列化与反序列化
- 序列化
序列化就是将一个对象变成二进制的比特流 可以把这个比特流保存到文件中 或者通过网络传输
- 反序列化
将序列化后的二进制比特流还原回原来的对象
- 简单来说就好比我们看大科幻电影 里面有很多的情节是这样的 将一个人或者物体变成一串数字和字母流 然后传送到很远的地方再将这一串数字和字母流变回原来的物体 这一过程和序列化反序列化很像 将物体变成数字字母流就是序列化 将数字字母流变成物体就是反序列化
为什么需要序列化?
- 当我们需要把内存中的对象状态保存到一个文件中或者数据库中时候
- 用套接字在网络上传送对象的时候
- 序列化最大的目的就是为了能让对象通过网络传输 能够保存在文件中 防止丢失找不到
实现Java对象的序列化与反序列化
- 如果对象要进行序列化需要实现Serializable接口
- ObjectOutputStream 用于序列化
- ObjectInputStream 用于反序列化
- transient修饰的变量不可以序列化
- static 修饰的变量不能被序列化
import java.io.*;
class Person implements Serializable {
public String name;
public int age;
public String sex;
transient public String cardId;
public static String phoneNum;
public Person(String name, int age, String sex, String cardId) {
this.name = name;
this.age = age;
this.sex = sex;
this.cardId = cardId;
}
public static void setPhoneNum(String phoneNum) {
Person.phoneNum = phoneNum;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", cardId='" + cardId + '\'' +
", phoneNum='" + phoneNum + '\'' +
'}';
}
}
public class SerializTest {
public static void main(String[] args) {
Person person = new Person("Listen", 21, "MAN", "100100100111");
Person.setPhoneNum("120");
serializPreson(person);
Person personRet = desSerializable();
System.out.println(personRet);
}
private static Person desSerializable() {
Person person = null;
try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\java\\java.txt"))){
person = (Person) objectInputStream.readObject();
System.out.println("反序列化成功");
} catch (IOException | ClassNotFoundException e) {
e.getStackTrace();
}
return person;
}
private static void serializPreson(Person person) {
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\java\\java.txt"))){
objectOutputStream.writeObject(person);
System.out.println("序列化成功");
} catch (IOException e) {
e.getStackTrace();
}
}
}
- 运行结果
- 我们可以看到cardId被transient修饰不能被序列化 所以得到的反序列化结果他的值就是null 但是我们说被static修饰的phoneNum也不能序列化 但是此处它尽然不显示null 这是因为 他是静态变量 在代码编译期间就已经存储在方法区的 所以他不需要序列化也可以获得值
关于serialVersionUID 的问题
- 如果序列化程序和反序列化程序不是用一个程序 然后俩个程序中都有一个Person类他们之间只有名字相同个别属性是不相同的 这时就会出现问题
- 这时就需要使用serialVersionUID 变量的值 这个变量无需手动设置(也可以手动设置但是不推荐) 编译器在编译的时候就会自动生成这个值(根据类的内容生成) 类的代码出现变化的时候 生成的这个uid值差距是很大的 所以在反序列化的时候 就可以检查这个uid的值 是否符合预期 就能判断当前类的代码是否一致