- 序列化和反序列化是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 + "]";
}
}