1、序列化是什么?
2、Java序列化为什么要实现Serializable?
3、为什么要明确定一个serialVersionUID,后期还不允许修改呢?
我们都知道在计算机世界是只认识二进制格式的数据的,所以如果我们想传输文件,保存文件,都需要将我们看到的转成二进制流(即byte[]数组)才能进行网络传输或者保存到磁盘。
将一个对象转成二进制流,这就是序列化。转为二进制流的对象就可以在网络之间进行传输,或者保存到磁盘。将这个二进制流再转为一个对象,就是反序列化。
本质就是将对象转为二进制流,然后再将二进制流转为对象
1、创建一个对象,序列化和反序列化这个对象
public class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
2、序列化和反序列化
public class SerializationDemo {
public static void main(String[] args) {
// 创建Person对象
Person person = new Person("John Doe", 30);
// 序列化对象到文件
try {
FileOutputStream fileOut = new FileOutputStream("person.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(person);
out.close();
fileOut.close();
System.out.println("Person对象已序列化到person.ser文件");
} catch (IOException e) {
e.printStackTrace();
}
// 从文件反序列化对象
try {
FileInputStream fileIn = new FileInputStream("person.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
Person deserializedPerson = (Person) in.readObject();
in.close();
fileIn.close();
System.out.println("从person.ser文件反序列化得到的Person对象:" + deserializedPerson);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
这个问题是因为Person类没有实现Serializable接口
1、我们来实现这个接口后再运行查看结果:
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 toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
我们看Serializable源码,发现它是一个空接口
public interface Serializable {
}
然后我们可以看源码的注释,注释说明只有类实现了此接口才能被标识为可以序列化。
由此我们发现这个接口就是起到一个标识的作用,在运行时被此接口标识的对象才能被序列化和反序列化,反之则不行。
我们看阿里巴巴开发手册中此规范被标识为【强制】
1、那这个是个什么东西呢?
从字面意思就发现是序列化版本id,就是这个对象序列化时的版本号,在我们实现serialVersionUID的时候虽然我们没有明确指定是多少,但是Java底层帮我们默认生成了一个随机数。
2、serialVersionUID不一致会怎么样
不一致就不能进行反序列化,只有反序列化的对象和二进制流的serialVersionUID是一致的才能反序列化。
有可能我们在序列化时对象是正常的,在反序列化时的对象是序列化的对象不一致了,就会报错。因为他们的serialVersionUID不一致
3、写一个demo测试一下
我们知道Java会默认生成一个随机数,所以对象属性发生变化时,serialVersionUID也会变化
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 toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
1、先将Person序列化到本地文件
/**
* 序列化对象到文件
*
* @param person
*/
public static void serialization(Person person, String fileName) {
// 序列化对象到文件
try {
FileOutputStream fileOut = new FileOutputStream(fileName);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(person);
out.close();
fileOut.close();
System.out.println("Person对象已序列化到person.ser文件");
} catch (IOException e) {
e.printStackTrace();
}
}
2、修改Person类,增加weight属性
public class Person implements Serializable{
private String name;
private int age;
private int weight;
public Person(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
public String toString() {
return "Person [name=" + name + ", age=" + age + ", weight=" + weight + "]";
}
}
3、反序列化之前序列化的文件
public static Person deserialization(String fileName) {
Person deserializedPerson = null;
// 从文件反序列化对象
try {
FileInputStream fileIn = new FileInputStream(fileName);
ObjectInputStream in = new ObjectInputStream(fileIn);
deserializedPerson = (Person) in.readObject();
in.close();
fileIn.close();
System.out.println("从person.ser文件反序列化得到的Person对象:" + deserializedPerson);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return deserializedPerson;
}
4、执行代码,我们发现报错了
意思就是两个serialVersionUID匹配不上不能反序列化
到这里我们就能明白,serialVersionUID不一样是不能进行反序列化的,也能明白为什么要求我们要自己定义一个serialVersionUID且后期不能修改,这样我们后期Person类不论改了什么属性都可以正常进行序列化和反序列化。
1、我们来实现这个demo
给原Person类加上serialVersionUID,然后序列化到本地文件
public class Person implements Serializable{
// 增加一个确定的serialVersionUID
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
2、修改Person属性,但是不要修改serialVersionUID值,然后对前面序列化的文件进行反序列化
public class Person implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private int age;
private int weight;
public Person(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
public String toString() {
return "Person [name=" + name + ", age=" + age + ", weight=" + weight + "]";
}
}
我们在IDEA中这样设置,在开发中如果实现了Serializable接口,但是没有写serialVersionUID属性,就会出现警告。
https://mp.weixin.qq.com/s/HP4P4IcD8oTEovBUSq54pA