目錄
文章目錄
內容
1、序列化流
1.1、序列化概述
之前我在存儲數據的時候,都是基本數據類型。但是當我們想要存儲對象的時候怎麼辦呢?Java提供了一種對象序列化機制。用一個字節序列表示一個對象,包括對象類信息,成員變量、成員方法信息等,然後寫入磁盤或者其他流中,相當於文件中持久化了一個對象,稱爲對象的序列化。
反之,該字節序列還可以讀取文件中的對象信息,重構對象,稱之爲對象的反序列化。
- 圖示1.1-1:
1.2、ObjectOutputStream
java.io.ObjectOutputStream類,把Java對象的原始數據類型持久化到文件中。
- 構造方法
參數列表 | 描述 |
---|---|
OutputStream out | 創建一個寫入指定的OutputStream的ObjectOutputStream |
- 常用方法
修飾符 | 返回值類型 | 方法名 | 參數列表 | 描述 |
---|---|---|---|---|
public | void | writeObject | Object obj | 將指定的對象寫入ObjectOutputStream。 |
1.2.1、序列化操作
-
滿足的條件:
- 該類必須實現java.io.Serializable接口,Serializable接口是序列化標記,不實現此接口的類的任何狀態不會被序列化和反序列化。
- 該類是所有屬性必須是可序列化的。如果有一個類型不需要序列化,必須註明是瞬態的,使用transient關鍵字聲明。
-
使用步驟:
- 創建ObjectOutputStream對象
- 調用ObjectOutputStream類的writeObject 方法,把對象寫入文件中
- 釋放資源
-
示例1.2.1-1:
package io.stream.serialize; import java.io.Serializable; public class Student implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String name; private int age; private char gender; private int score; public Student() {} public Student(String name, int age, char gender, int score) { this.name = name; this.age = age; this.gender = gender; this.score = score; } 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; } public char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } @Override public String toString() { return name + "\t" + age + "\t" + gender + "\t" + score; } } package io.stream.serialize; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class TestSeriabliable1 { public static void main(String[] args) throws FileNotFoundException, IOException { Student s = new Student("gaogzhen", 32, '男', 8000); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f:\\test\\b.txt")); oos.writeObject(s); oos.close(); } } 測試結果:b.txt內容 sr io.stream.serialize.Student I ageC genderI scoreL namet Ljava/lang/String;xp u7 @t gaogzhen 字節碼文件,直接打開,看不懂
1.3、ObjectInputStream
&esmp; ObjectInputStream類,把之前ObjectOutputStream類序列化到文件中的對象,反序列化之後,重構爲對象。
- 構造方法:
參數列表 | 描述 |
---|---|
InputStream in | 創建從指定的InputStream讀取的ObjectInputStream。 |
- 常用方法
修飾符 | 返回值類型 | 方法名 | 參數列表 | 描述 |
---|---|---|---|---|
public | Object | readOject | 從ObjectInputStream讀取一個對象。 |
-
使用步驟:
- 創建ObjectOutputStream對象
- 調用ObjectOutputStream類的writeObject 方法,把對象寫入文件中
- 釋放資源
-
示例:1.3-1:讀取b.txt序列化的對象並顯示
package io.stream.serialize; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; public class TestUnSerialize1 { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("f:\\test\\b.txt")); Student s = (Student) ois.readObject(); ois.close(); System.out.println(s); } } 測試結果: gaogzhen 32 男 8000
1.4、transient關鍵字
意爲瞬態,被transient修飾的成員變量不能被序列化
-
示例1.4-1:
上例中的Student 的age 用transient修飾 private transient int age; package io.stream.serialize; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class TestTransient1 { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { Student s = new Student("gaogzhen", 32, '男', 8000); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f:\\test\\b.txt")); oos.writeObject(s); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("f:\\test\\b.txt")); Student s1 = (Student) ois.readObject(); ois.close(); System.out.println(s1); } } 測試結果: gaogzhen 0 男 8000
1.5、InvalidClassException
當JVM反序列化對象時,能找到class文件,但是class文件的序列化對象之後發生了修改,那麼反序列化操作會失敗,拋出InvalidClassException異常。發生此異常的原因:
- 該類的序列號於從六種讀取的類描述符的版本號不匹配
- 該類包含未知的數據類型
- 該類沒有可訪問的無參構造函數
1.6、serialVersionUID
serialVersionUID的取值是Java運行時環境根據類的內部細節自動生成的。如果對類的源代碼作了修改,再重新編譯,新生成的類文件的serialVersionUID的取值有可能也會發生變化。
類的serialVersionUID的默認值完全依賴於Java編譯器的實現,對於同一個類,用不同的Java編譯器編譯,有可能會導致不同的 serialVersionUID,也有可能相同。爲了提高serialVersionUID的獨立性和確定性,強烈建議在一個可序列化類中顯示的定義serialVersionUID,爲它賦予明確的值。
顯式地定義serialVersionUID有兩種用途:
1、 在某些場合,希望類的不同版本對序列化兼容,因此需要確保類的不同版本具有相同的serialVersionUID;
2、 在某些場合,不希望類的不同版本對序列化兼容,因此需要確保類的不同版本具有不同的serialVersionUID。
2、打印流
java.io.PrintStream打印流。PrintStream爲其他輸出流添加了功能,使它們能夠方便的打印各數據值表示形式。
-
特點
- 只負責數據的輸出,不負責數據的讀取
- 與其它輸出流不同,PrintStream永遠不會拋出IOException
-
特有方法
- void print(任意類型):打印任意類型的數據
- void println(任意類型):打印任意類型的數據,並且換行
-
構造方法
參數列表 | 描述 |
---|---|
File file | 輸出目的地爲文件 |
String fileName | 輸出目的地文件 |
OutputStream out | 輸出到其他流 |
- 繼承自父類的方法
修飾符 | 返回值類型 | 方法名 | 參數列表 | 描述 |
---|---|---|---|---|
public | void | close | 關閉流,釋放資源 | |
public | void | flush | 刷新此輸出流,並強制任何緩衝的字節寫出 | |
public | void | write | byte[] b | 將 b.length字節從指定的字節數組寫入此輸出流。 |
public | void | write | byte[] b, int off, int len | 從指定的字節數組寫入 len個字節,從偏移 off開始到此流。 |
public abstract | void | write | int b | 將指定的字節寫入此流。 |
-
注意:
- 如果使用繼承自父類的write方法寫數據,那麼查看數據的時候會查看編碼表
- 如果使用特有的print或者println方法寫數據,原樣輸出
-
示例2-1:
package io.stream.print; import java.io.PrintStream; public class TestPrintStream1 { public static void main(String[] args) { PrintStream ps = new PrintStream(System.out); ps.write(97); ps.println(); ps.println(97); } } 測試結果: a 97
後記 :
本項目爲參考某馬視頻開發,相關視頻及配套資料可自行度娘或者聯繫本人。上面爲自己編寫的開發文檔,持續更新。歡迎交流,本人QQ:806797785
前端項目源代碼地址:https://gitee.com/gaogzhen/vue-leyou
後端JAVA源代碼地址:https://gitee.com/gaogzhen/JAVA