一、关于serializableUID
反序列化的时候serializableUID要跟序列化的保持一致,反序列化才会成功,如果序列化和反序列化都没有serializableUID也是可行的。
序列化和反序列化修改文件时需要注意的点:
1、如果序列化对象的serializableUID是用集成工具自动生成的,序列化对象的时候用了这个serializableUID,反序列化之前如果把序列化对象的serializableUID去掉的话,反序列化是可以成功的,因为默认会自动生成一个一模一样的serializableUID;如果序列化对象的时候自己设定一个serializableUID,反序列化之前把这个serializableUID去掉了,反序列化就不会成功,因为反序列化默认生成的serializableUID跟序列化的serializableUID不一致。
2、当不指定serializableUID的时候,即使反序列化之前对这个对象增加空格和换行,反序列化也是可以成功的,因为这两步操作生成的serializableUID是一样的,但是如果反序列化之前对象中添加了一些属性,则不会反序列化成功,因为serializableUID的生成方法是根据对象的属性生成的,两步操作serializableUID不一致。
3、当指定serializableUID的时候,序列化以后,给对象增加新的属性,反序列化是可以成功的,只不过新增的属性的值为null。
二、关于静态成员
1、静态变量是不能够被序列化的,静态成员是随着类的加载而加载的,与类共存亡的,而序列化是针对对象的。
(1)测试过程如下:首先在类里面设置一个静态变量age,比如设置初始值为5,序列化写入文件(比如Test.txt)之前给这个静态重新赋值为3,然后运行main方法开始序列化;序列化以后,开始反序列化,也是运行main方法,会发现这个静态变量age打印出来的值为5,而不是3。
(2)可能存在的坑:运行main方法的时候,序列化和反序列化不要一起运行,一起运行的话,这样序列化加载类的时候,JVM首先会把静态变量age初始化为5,后面重新赋值为3,反序列化的时候,因为是同一个进程,会直接从JVM中获取静态变量age=3,所以最后打印的值是3。如果序列化和反序列化分开运行的话,序列化方法main执行,启动JVM,age=3,main执行完毕,此时JVM退出;反序列化main开始执行,重新启动JVM,加载类,初始化,age=5,main执行完毕,JVM退出,打印的值age=5。
三、关于父类、子类
1、如果父类实现了Serializable,子类不用实现,会自动进行序列化。
2、如果父类没实现Serializable,子类实现Serializable,只能进行子类的序列化,父类不会序列化。
四、利用序列化实现深克隆
public class Student implements Serializable{
private static final long serialVersionUID = -6100391738494786200L;
private String name;
private int age;
private Teacher teacher;
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 Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public Object deepClone() throws IOException, ClassNotFoundException {
//序列化
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
oos.writeObject(this);
//反序列化
ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bais);
return ois.readObject();
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", teacher=" + teacher +
'}';
}
}
public class Teacher implements Serializable {
private static final long serialVersionUID = 8389453983965559287L;
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
public class SerializableCloneDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Teacher teacher=new Teacher();
teacher.setName("老师");
teacher.setSex("女");
Student student=new Student();
student.setName("学生");
student.setAge(18);
student.setTeacher(teacher);
Student student1=(Student)student.deepClone();
student1.getTeacher().setName("老师111");
System.out.println(student);
System.out.println(student1);
}
}
由结果可以看出实现了深克隆:Student引用Teacher,student1修改Teacher的属性,并没有影响原来的Student里面的Teacher对象,由此可见,student和student1的teacher的引用并不是同一个对象,而深克隆不仅要把原有对象的变量都复制一份,而且原有对象所引用的对象都复制了一遍。
Serializable补充:
1、关键字transient加到对象哪个属性前面,哪个属性就不被序列化。
2、如果一个对象A引用对象B,如果对象A进行序列化,会自动也把对象B进行序列化,前提是A和B都要实现Serializable才可以。
水平有限,希望读者多多批评指正,感谢!