endnote x9.3.3 for windows安裝教程
阿新 • • 發佈:2021-07-15
1.序列化與反序列化的概念
•序列化:將物件寫入到IO流中
•反序列化:從IO流中恢復物件
序列化機制允許將這些實現序列化介面的物件轉化為位元組序列,這些位元組序列可以保證在磁碟上或者網路傳輸後恢復成原來的物件。序列化就是把物件儲存在JVM以外的地方,序列化機制可以讓物件脫離程式的執行而獨立存在。
public class People implements Serializable { private Long id; public People(Long id) { this.id = id; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Override public String toString() { return "People{" + "id=" + id + '}'; } } public class SerTest { /** * <h1>序列化和反序列化 People 物件</h1> */ private static void testSerializablePeople() throws Exception { // 序列化的步驟 // 用於儲存序列化的檔案,這裡的java_下劃線僅僅為了說明是java序列化物件,沒有任何其他含義 File file = new File("/tmp/people_10.java_"); if (!file.exists()) { // 1,先得到檔案的上級目錄,並建立上級目錄 file.getParentFile().mkdirs(); try { // 2,再建立檔案 file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } People p = new People(10L); // 建立一個輸出流 ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(file) ); // 輸出可序列化物件 oos.writeObject(p); // 關閉輸出流 oos.close(); // 反序列化的步驟 // 建立一個輸入流 ObjectInputStream ois = new ObjectInputStream( new FileInputStream(file) ); // 得到反序列化的物件,這裡可以強轉為People型別 Object newPerson = ois.readObject(); // 關閉輸入流 ois.close(); System.out.println(newPerson); } public static void main(String[] args) throws Exception { testSerializablePeople(); } } 2.子類實現Serializable介面,父類沒有實現,子類可以序列化嗎?
public class People {
private Long id;
public People(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return "People{" +
"id=" + id +
'}';
}
}
public class Worker extends People implements Serializable {
private String name;
public Worker(Long id, String name) {
super(id);
this.name = name;
}
}
public class SerTest {
/**
*
序列化和反序列化 People 物件
*/
private static void testSerializablePeople() throws Exception {
// 序列化的步驟 // 用於儲存序列化的檔案,這裡的java_下劃線僅僅為了說明是java序列化物件,沒有任何其他含義 File file = new File("/tmp/people_10.java_"); if (!file.exists()) { // 1,先得到檔案的上級目錄,並建立上級目錄 file.getParentFile().mkdirs(); try { // 2,再建立檔案 file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } //People p = new People(10L); People p = new Worker(10L, "lcy"); // 建立一個輸出流 ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(file) ); // 輸出可序列化物件 oos.writeObject(p); // 關閉輸出流 oos.close(); // 反序列化的步驟 // 建立一個輸入流 ObjectInputStream ois = new ObjectInputStream( new FileInputStream(file) ); // 得到反序列化的物件,這裡可以強轉為People型別 Object newPerson = ois.readObject(); // 關閉輸入流 ois.close(); System.out.println(newPerson); } public static void main(String[] args) throws Exception { testSerializablePeople(); }
}
![](https://img2020.cnblogs.com/blog/2197916/202107/2197916-20210720202918846-1236896739.png)
結果顯示沒有有效地構造器,原來是因為父類沒有序列化的時候,Object newWorker = ois.readObject()需要直接呼叫父類的無引數構造方法,不經過子類的無參構造方法。
我們在父類People中加上空的構造方法之後再次執行
public class People {
private Long id;
public People(Long id) {
this.id = id;
}
public People() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return "People{" +
"id=" + id +
'}';
}
}
![](https://img2020.cnblogs.com/blog/2197916/202107/2197916-20210720203044321-1421260381.png)
結果卻發現列印的不是Worker,而是父類People,因為子類沒有實現toString而呼叫父類的toString,所以列印了People物件,至於父類成員變數id為什麼是null,原因如下:
1、一個子類實現了 Serializable 介面,它的父類都沒有實現 Serializable介面,序列化該子類物件。要想反序列化後輸出父類定義的某變數的數值,就需要讓父類也實現Serializable介面或者父類有預設的無參的建構函式。
2、在父類沒有實現Serializable 介面時,虛擬機器是不會序列化父物件的,而一個 Java物件的構造必須先有父物件,才有子物件,反序列化也不例外。所以反序列化時,為了構造父物件,只能呼叫父類的無參建構函式作為預設的父物件。因此當我們取父物件的變數值時,它的值是呼叫父類無參建構函式後的值,如果在父類無參建構函式中沒有對變數賦值,那麼父類成員變數值都是預設值,如這裡的Long型就是null。
3、根據以上特性,我們可以將不需要被序列化的欄位抽取出來放到父類中,子類實現 Serializable介面,父類不實現Serializable介面但提供一個空構造方法,則父類的欄位資料將不被序列化。
總結:
•子類實現Serializable介面,父類沒有實現,子類可以序列化!
•這種情況父類一定要提供空構造方法,不要忘了子類的toString方法!
3.類中存在引用物件,這個類物件在什麼情況下可以實現序列化?
public class Combo implements Serializable {
private int id;
private People people;
public Combo(int id, People people) {
this.id = id;
this.people = people;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public People getPeople() {
return people;
}
public void setPeople(People people) {
this.people = people;
}
@Override
public String toString() {
return "Combo{" +
"id=" + id +
", people=" + people +
'}';
}
}
public class People {
private Long id;
public People(Long id) {
this.id = id;
}
public People() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return "People{" +
"id=" + id +
'}';
}
}
public class SerTest {
/**
*
序列化和反序列化 People 物件
*/
private static void testSerializablePeople() throws Exception {
// 序列化的步驟
// 用於儲存序列化的檔案,這裡的java_下劃線僅僅為了說明是java序列化物件,沒有任何其他含義
File file = new File("/tmp/people_10.java_");
if (!file.exists()) {
// 1,先得到檔案的上級目錄,並建立上級目錄
file.getParentFile().mkdirs();
try {
// 2,再建立檔案
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
People p = new People(10L);
//People p = new Worker(10L, "lcy");
Combo c = new Combo(1, p);
// 建立一個輸出流
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(file)
);
// 輸出可序列化物件
oos.writeObject(c);
// 關閉輸出流
oos.close();
// 反序列化的步驟
// 建立一個輸入流
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(file)
);
// 得到反序列化的物件,這裡可以強轉為People型別
Object newPerson = ois.readObject();
// 關閉輸入流
ois.close();
System.out.println(newPerson);
}
public static void main(String[] args) throws Exception {
testSerializablePeople();
}
}
![](https://img2020.cnblogs.com/blog/2197916/202107/2197916-20210720203949323-890704154.png)
直接爆出異常,說明People類沒有序列化。
當People加上implements Serializable實現序列化介面後,再次執行如下
![](https://img2020.cnblogs.com/blog/2197916/202107/2197916-20210720204043226-323637941.png)
總結:
•一個類裡面所有的屬性必須是可序列化的,這個類才能順利的序列化。
4.同一個物件多次序列化之間有屬性更新,前後的序列化有什麼區別?
public class SerTest {
/**
*
序列化和反序列化 People 物件
*/
private static void sameObjectRepeatedSerialization() throws Exception {
File file = new File("/tmp/peopele_more.java_");
if (!file.exists()) {
// 1,先得到檔案的上級目錄,並建立上級目錄
file.getParentFile().mkdirs();
try {
// 2,再建立檔案
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
People p = new People(10L);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
// 未序列化,先修改屬性
p.setId(11L);
oos.writeObject(p);
// 序列化一次後,再次修改屬性
p.setId(15L);
oos.writeObject(p);
// 序列化兩次後,再次修改屬性
p.setId(20L);
oos.writeObject(p);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
Object people1 = ois.readObject();
ois.close();
System.out.println(((People) people1).getId());
}
public static void main(String[] args) throws Exception {
sameObjectRepeatedSerialization();
}
}
總結:
•當第一次序列化之後,不管如何修改這個物件的屬性,都不會對後續的序列化產生影響,反序列化的結果都和第一次相同。