问题描述
在开发中我们会经常使用自定义异常类,或者使用对象流,在自定义异常类中,我们需要继承Exception
或RuntimeException
,并且需要提供serialVersionUID
的属性,而在使用对象流中自定义类需要实现Serializable
(标识)接口,也同要需要提供一个serialVersionUID
的属性,那么这是为什么呢?让我们看一下源码:
1.Exception类中的serialVersionUID属性
2.Serializable接口中的注释
提示:其实在Serializable接口的注释中已经对问题进行了解释,但是我们留到后面去说
错误演示:
我们先演示如果不按照规则进行会出现什么问题。
注意:开发中,需要使用try-catch-finally方式处理流的异常
1.我们随便定义一个JavaBean
import java.io.Serializable;
public class Person implements Serializable {//Serializable:属于一个标识接口
transient String name;
static int age;
int id;
// String nationality = "China";//国籍
// static final long serialVersionUID = 423216156564656L;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, int id) {
this.name = name;
this.age = age;
this.id = id;
}
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 int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
2.再定义一个测试类
import org.junit.Test;
import java.io.*;
public class PersonTest {
/**
* 演示自定义类的对象的序列化和反序列化过程
* 序列化过程
*/
@Test
public void test1() throws IOException {
//1.创建File类的对象
File file = new File("object.txt");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
//2.写出数据即为序列化过程
Person p1 = new Person("Tom", 18);
oos.writeObject(p1);
oos.flush();
Person p2 = new Person("Jerry", 23, 1221);
oos.writeObject(p2);
oos.flush();
//3.关闭资源
oos.close();
}
/**
* 演示自定义类的对象的序列化和反序列化过程
* 反序列化过程
*/
@Test
public void test2() throws IOException, ClassNotFoundException {
//1.创建File类的对象
File file = new File("object.txt");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
//2.读取文件中的对象(或反序列化的过程)
Person person = (Person) ois.readObject();
System.out.println(person);
Person person1 = (Person) ois.readObject();
System.out.println(person1);
//3.关闭资源
ois.close();
}
}
先运行test1
再运行test2
test1中我们将数据写入到Objtct.txt类中,再通过test2反序列化将Objtct.txt中的数据转换成对象流,可以看到运行结果没有问题,非常正常,这是因为在序列化过程中,会自动给自定义类创建一个serialVersionUID
,而在反序列化中也会使用这个id来找到这个类进行反序列化,而我们一旦对原本的Person类进行修改(将国籍属性取消注释),那么再次运行又会重新生成一个serialVersionUID
,从而导致原有的Objtct.txt中的数据因为找不到原来的serialVersionUID
而不能再转换成对象流。
将国籍注释打开
再次运行test2从Objtct.txt读取文件中的对象
可以看到报错信息显示:
java.io.InvalidClassException: java05_objectstream.demo.Person; local class incompatible: stream classdesc serialVersionUID = 1027002611310758675, local class serialVersionUID = -135851562499732227
意思是:
本地类不兼容:
流classdesc serialVersionUID = 1027002611310758675,
本地类serialVersionUID = -135851562499732227
因为对象流中保存的serialVersionUID 与本地类的serialVersionUID 不一致导致
显示定义serialVersionUID :
static final long serialVersionUID = 423216156564656L;//数值随便输
如果声明了serialVersionUID,即使在序列化完成之后修改了类导致类重新编译,则原来的数据也能正常反序列化,只是新增的字段值是默认值而已。
总结
static final long serialVersionUID = 42L;