1. 序列化和反序列化的定义
- 序列化:把Java对象转化为字节序列的过程
- 反序列化:把字节序列恢复为Java对象的过程
2. 序列化和反序列化的作用
-
序列化最重要的作用:在传递和保存对象时.保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中(在JVM停止运行之后能够持久化指定的对象)。
-
反序列化的最重要的作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。
总结:核心作用就是对象状态的保存和重建。(整个过程核心点就是字节流中所保存的对象状态及描述信息)
注意:
- static 属性不参与对象的序列化,在进行序列化的时候,序列化其实上是对象最后一次状态的改变,也就是把内存中的对象的状态持久化到了文件中。
- transient 关键字阻止该变量被序列化到文件中。在变量声明前加上 transient 关键字,可以阻止该变量被序列化到文件中,在被反序列化后, transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
打个比方我们在进行信息传递的过程中有一些敏感信息例如密码是不能够进行传输的,这时候我们就需要在密码属性前面添加transient关键字,使密码属性跳出对象序列化的范围中,所以在一定程度上保证了该信息的安全。
上代码
public class Student implements Serializable {
private static final long serialVersionUID = 54654563131552L;
private String name;
private int age;
private static String sex = "男";
private transient String password;
public Student(String name, int age, String password) {
this.name = name;
this.age = age;
this.password = password;
}
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 static String getSex() {
return sex;
}
public static void setSex(String sex) {
Student.sex = sex;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", password='" + password + '\'' +
'}';
}
}
public class Test {
public static void main(String[] args) {
//序列化
try {
OutputStream opOutputStream = new FileOutputStream("test.txt");
ObjectOutputStream opStream = new ObjectOutputStream(opOutputStream);
opStream.writeObject(new Student("sherlock", 18, "root"));
opStream.close();
} catch (Exception e) {
e.printStackTrace();
}
//反序列化
try {
InputStream inputStream = new FileInputStream("test.txt");
ObjectInputStream oStream = new ObjectInputStream(inputStream);
byte[] buffer = new byte[10];
int len = -1;
Student student = (Student) oStream.readObject();
System.out.println(student);
oStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
控制台输出:
image.png
可以发现transient 关键字确实阻止了该变量被序列化到文件中,将该变量赋为了默认值。
3. 序列化ID
java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。(两次的序列化ID不一致会导致反序列化失败)
比如我们把上面的序列化ID改为54654563131551L,控制台就会报以下的异常
image.png
当我们一个实体类中没有显示的定义一个名为“serialVersionUID”、类型为long的变量时,Java序列化机制会根据编译时的class自动生成一个serialVersionUID作为序列化版本比较,这种情况下,只有同一次编译生成的class才会生成相同的serialVersionUID。譬如,当我们编写一个类时,随着时间的推移,我们因为需求改动,需要在本地类中添加其他的字段,这个时候再反序列化时便会出现serialVersionUID不一致,导致反序列化失败。那么如何解决呢?便是在本地类中添加一个“serialVersionUID”变量,值保持不变,便可以进行序列化和反序列化。
网友评论