Java基础之序列化
最近幾天重新看了下序列化部分的內容,今天將它整理出來。
序列化是java開發中經常可以聽到的一個詞,那么究竟什么是序列化呢?簡單來理解的話就是:將java對象轉換成字節序列以二進制數據的形式保存在本地的操作就叫做序列化,將二進制數據還原成java對象的過程就叫反序列化。
???? 我們畫一個圖來說明下:
2.怎么讓對象序列化/反序列化
? 雖然序列化的目的是為了操作java對象,但并不是所有的java對象都可以進行序列化,想要實現序列化首需實現Serializable接口或者Externalizable接口,本文主要介紹Serializable接口。
????? 我們先來看下java.io.Serializable接口:
可以看到這個接口僅僅是個標記,代表這個類可以序列化,沒有任何方法,通過上面的@see注解可以知道它和對象處理流有關。
????? 現在我們已經知道只要一個類實現了Serializable接口,就代表這個類可以序列化,那么通過什么操作可以將這個java對象以二進制數據的形式保存到本地呢?就是上面@see提到的對象處理流ObjectStream,我們寫一個實例來了解一下整個過程:
可序列化的java對象:
package com.ljw.serialzable;import java.io.Serializable;/*** @author liu.jiawei* @create 2018-08-29 22:52**/ public class Dog implements Serializable{public String type;public String name;public int age;public Dog(String type, String name, int age) {this.type = type;this.name = name;this.age = age;}public String getType() {return type;}public void setType(String type) {this.type = type;}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;} }序列化過程:
package com.ljw.serialzable;import java.io.*;/*** @author liu.jiawei* @create 2018-08-29 22:29**/ public class TestSerializeDog {public static void main(String[] args) {File file = new File("Dog.txt");try (FileOutputStream fis = new FileOutputStream(file);ObjectOutputStream oos = new ObjectOutputStream(fis)) {Dog dog = new Dog("藏獒", "旺財", 1);oos.writeObject(dog);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}運行結果:
可以看到通過ObjectOutputStream這個對象處理流,可以實現java對象的序列化,處理流需要基于節點流發揮作用,ObjectOutputStream需要配合FileOutputStream一起使用。
?
看了序列化的過程,我們再將保存dog對象的文件重新還原成java對象:
package com.ljw.serialzable;import java.io.*;/*** @author liu.jiawei* @create 2018-08-29 23:01**/ public class TestDeserializeDog {public static void main(String[] args) {File file = new File("/Users/liujiawei/ztesoft/JSYD/leetcode/dog.txt");try (FileInputStream fis = new FileInputStream(file);ObjectInputStream ois = new ObjectInputStream(fis)) {Dog dog = (Dog) ois.readObject();System.out.println(dog.getType() + "===" + dog.getName() + "===" + dog.getAge());} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}} }可以看到,與序列化過程基本相似,只是ObjectOutputStream換成了ObjectInputStream,writeObject換成了readObject,類型強轉程了需要的java 對象,這樣就將之前的二進制數據還原成了對應的java對象。
? 還是上面的圖來說明下過程:
3.序列化中的注意細節
- serialVersionUID
通過上面的兩個例子,我們已經大概了解序列化和反序列化的過程,還有些細節需要我們注意,還是上面的dog對象,我們增加一個成員變量:
public int height;再重新執行一下剛剛的反序列化的代碼,是不是覺得很奇怪,這個兩者有什么聯系么?我們運行下代碼:
是不是運行出錯了,看它的報錯提示我們可以知道有兩個id不同導致了報錯,這個id是干什么的呢?
???? 這里面涉及到一個概念叫序列id(serialVersionUID),這個jvm在序列化操作文件時用來判斷的一個變量,一般來說同一個class文件在不同情況編譯的出來的serialVersionUID都是不同的,這就會導致了上面的那個情況,所以我們在聲明一個java類是可序列化的時候,同時會定義一個靜態常量serialVersionUID,idea可以對class生成對應的serialVersionUID,或者直接加上:
public static final long serialVersionUID = 1L;*多個class可以用同一個serialVersionUID,并不影響判斷。
?
我們在Dog類中加上serialVersionUID,重新執行反序列化過程,可以正常執行。
?
- transient
? 一個可序列化的java對象,有些時候,我們并不想暴露所有的成員變量,只需要在對應的變量前加上transient關鍵字,那么這個變量就不會被被序列化了,在反序列化的時候也就只能獲取對應類型的默認值了。
???? 我們將Dog類中的年齡字段隱藏:
public transient int age;重新執行下反序列化過程,看下運行結果有沒有不同:
?可以看到,我們雖然反序列化了對象,但是并沒有拿到隱藏的字段的值。
?
?
4.序列化思考
? (1)子類沒有實現序列化接口,基類實現,子類可以序列化么?
? (2)子類實現序列化接口,基類沒有實現,子類可以序列化么?
(3)內部類實現序列化接口,外部類沒有實現,內部類可以序列化么?
???? ?廢話不多說,直接上代碼來一個個測試下:
(1):
???? 子類:
package com.ljw.serialzable;/*** @author liu.jiawei* @create 2018-08-29 23:35**/ public class Man extends Person{public String name;public Man(String sex) {super(sex);}public String getName() {return name;}public void setName(String name) {this.name = name;} }???? 基類:
package com.ljw.serialzable;import java.io.Serializable;/*** @author liu.jiawei* @create 2018-08-29 23:34**/ public class Person implements Serializable {public String sex;public Person(String sex) {this.sex = sex;} }???? 序列化:
package com.ljw.serialzable;import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream;/*** @author liu.jiawei* @create 2018-08-29 23:36**/ public class TestSerializeMan {public static void main(String[] args) {try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("man.txt"))) {oos.writeObject(new Man("man"));} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}} }運行結果:
結論:可以
?
(2)
子類:
package com.ljw.serialzable;import java.io.Serializable;/*** @author liu.jiawei* @create 2018-08-29 23:39**/ public class Cat extends Animal implements Serializable{public String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public Cat(String type) {super(type);}public Cat(String type, String name) {super(type);this.name = name;} }基類:
package com.ljw.serialzable;/*** @author liu.jiawei* @create 2018-08-29 23:39**/ public class Animal {public String type;public Animal(String type) {this.type = type;} }序列化:
package com.ljw.serialzable;import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream;/*** @author liu.jiawei* @create 2018-08-29 23:40**/ public class TestSerializeCat {public static void main(String[] args) {try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("cat.txt"))) {oos.writeObject(new Cat("波斯貓"));} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}} }?運行結果:
?
?
???? 結論:可以
(3)
???? 包含內部類的外部類:
package com.ljw.serialzable;import com.ljw.ColleactionAndMap.T;import java.io.*;/*** @author liu.jiawei* @create 2018-08-29 23:43**/ public class TestInnerClass {class Dog implements Serializable{public String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public Dog(String name) {this.name = name;}}public static void main(String[] args) {try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ddd.txt"))) {TestInnerClass testInnerClass = new TestInnerClass();TestInnerClass.Dog dog = testInnerClass.new Dog("旺財");oos.writeObject(dog);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}} }運行結果:
結論:不可以,外部類也必須實現序列化接口。?????
?
?
?
?
?
總結
以上是生活随笔為你收集整理的Java基础之序列化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Axure实现原型设计(一)
- 下一篇: 前端必备的开发工具推荐——VScode代