序列化:将java对象转化为字节序列的过程。
反序列化:将字节序列转化为java对象的过程。
在进行远程通信时,如果需要传输java对象:发送方需要把java对象转换为字节序列(也就是序列化),接收方需要将字节序列转换为java对象(也就是反序列化)。
序列化的好处是实现了数据的持久化,通过序列化可以将数据永久地保存到硬盘上,也可以将对象进行网络传输。
java.io.ObjectOutputStream表示对象输出流,writeObject(Object obj)方法可以将obj对象序列化,把得到的字节序列写入输出流中。
java.io.ObjectInputStream表示对象输入流,readObject()方法输入流中读取字节序列,再把它们反序列化成一个对象,并返回。
只有实现了Seriizable或Externalizable接口的类对象才能被序列化,否则会抛出异常。
序列化与反序列化功能的代码
/**
* 序列化与反序列化
*
* @author hu
* @date 2023/02/02 11:22
*/
public class SerialTest {
// 序列化
public static void serialize() throws IOException {
// 声明Person对象
Person person = new Person();
person.setName("hu");
person.setAge(18);
person.setScore(1000);
// 序列化并持久化到person.txt文件中
ObjectOutputStream objectOutputStream =
new ObjectOutputStream(new FileOutputStream(new File("person.txt")));
objectOutputStream.writeObject(person);
objectOutputStream.close();
System.out.println("序列化成功!已经生成person.txt文件");
System.out.println("==============================================");
}
// 反序列化
public static void deserialize() throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream =
new ObjectInputStream(new FileInputStream(new File("person.txt")));
Person person = (Person) objectInputStream.readObject();
objectInputStream.close();
System.out.println("反序列化结果为:");
System.out.println(person);
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
serialize();
deserialize();
}
}
class Person implements Serializable {
private String name;
private Integer age;
private Integer score;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
}
Serializable接口的作用
Serializable接口并没有任何方法,只是一个声明式接口,标记类是否可以序列化和反序列化。
serialVersionUID的作用
反序列化需要serialVersionUID来判断版本是否一致。如果序列化的serialVersionUID与反序列化的serialVersionUID不同则无法完成反序列化。只有相同才能完成反序列化。类似于解决乐观锁ABA问题的version。
怎样排除敏感字段
可能遇到的场景就是在序列化时有些敏感字段不方便被保留,比如用户密码,会造成安全性问题。这时候我们该怎么办呢?
使用transtient修饰不想序列化的字段
transtient修饰符是标记不需要持久化的字段。
使用Externalizable接口
Externalizable接口继承与Serializable接口,目的是满足可扩展性,让你自行实现序列化逻辑。
在学习序列化相关知识的时候,看到有人说使用static修饰的字段也可以达到序列化屏蔽字段的效果。但是本人在测试的时候并没有体现出来。有大佬懂的话,也希望给小弟解解惑。
class Person implements Serializable {
private String name;
private static Integer age;
private transient Integer score;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
Person.age = age;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
}