- 序列化和反序列化是java中进行数据存储和数据传输的一种方式。序列化是把对象转化为字节的过程,反序列化反之。
- 序列化的场景?
- 网络通信中以字节传输
- 数据的存储
- 如何序列化?
- 实现Serializable 接口
- 实现Externalizable 接口,其中Externalizable 接口继承了Serializable 接口
- 需求:将User 类序列化到 test.txt 文件中
(1)User 类实现Serializable 接口,添加生成serialVersionUID
public class User implements Serializable {
private static final long serialVersionUID = 7262143984388335055L;
private String name;
private Integer age;
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;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
(2)测试类
public class TestSerializable {
public static void main(String[] args) {
User user = new User();
user.setName("testname");
user.setAge(20);
serialize(user);//序列化对象
User u = (User) deserialize();//反序列化
System.out.println(u);
}
private static void serialize(Serializable sobj) {
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.txt"));
oos.writeObject(sobj);
oos.flush();
oos.close();
} catch (Exception e) {
System.out.println("序列化失败");
e.printStackTrace();
}
System.out.println("序列化成功");
}
private static Object deserialize() {
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test.txt"));
Object obj = ois.readObject();
ois.close();
System.out.println("反序列化成功");
return obj;
} catch (Exception e) {
System.out.println("反序列化失败");
e.printStackTrace();
}
return null;
}
}
(3)结果
序列化成功
反序列化成功
User [name=testname, age=20]
- serialVersionUID 有何作用?
是序列化和反序列化的标识,只有ID 相同才能成功转换。删除serialVersionUID 的情况种,当已经序列化在文件之中,然后修改User 类,之后反序列化会报错。
- transient 关键字与Externaliable 运用场景
- 当User 类很多属性时,只有一个或几个不需要序列化,在属性前添加transient 关键字。
- 当User 类很多属性时,只有一个或几个需要序列化时,实现Externalizable 接口来对这个或这些属性序列化。
- 第一种就不演示了,下面是第二种实现Externalizable 接口,必须重写两个方法,当序列化时会自动调用,测试类不变。
问题:为什么实现 Externalizable 接口不用serialVersionUID ?
Externalizable的反序列化和serializable不一样,它会在反序列化时调用对象的默认构造函数来创建这个对象,然后利用void readExternal(ObjectInput in)中的对相应的属性的进行初始化。如果没有该默认构造函数,会报错。
public class User implements Externalizable {
private String name;
private Integer age;
/**序列化时自动调用*/
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(this.name);
}
/**反序列化时自动调用*/
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.name = in.readUTF();
}
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;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
运行结果
序列化成功
反序列化成功
User [name=testname, age=null]
- 加密后再序列化,反序列化后再解密
public class User implements Serializable {
private static final long serialVersionUID = 7262143984388335055L;
private String name;
private Integer age;
//调用ObjectOutputStream.writeObject 的时候自动调用
private void writeObject(ObjectOutputStream oos) throws Exception {
Base64.Encoder encoder = Base64.getEncoder();
byte[] array = encoder.encode(this.name.getBytes());
this.name =new String(array);
oos.defaultWriteObject();
}
//调用ObjectInputStream.readObject 的时候自动调用
private void readObject(ObjectInputStream ois) throws Exception {
ois.defaultReadObject();//先反序列化
Base64.Decoder decoder = Base64.getDecoder();
byte[] bs = decoder.decode(this.name);
this.name=new String(bs);
}
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;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}