從屌絲到架構(gòu)師的飛越(IO流篇)-序列化流

一.介紹

序列化流:把對象按照流一樣的方式存入文本文件或者在網(wǎng)絡(luò)中傳輸?! ? 對象 -- 流數(shù)據(jù)(ObjectOutputStream)

反序列化流:把文本文件中的流對象數(shù)據(jù)或者網(wǎng)絡(luò)中的流對象數(shù)據(jù)還原成對象。流數(shù)據(jù) -- 對象(ObjectInputStream)

序列化流和反序列化流不同于字節(jié)流、字符流、內(nèi)存字節(jié)流,這些都是把字符串寫入/讀取文件,序列化流和反序列化流可以將對象寫入/讀取文本文件中.

但是我們要注意的是,寫入和讀取的文件要實現(xiàn)Serializable這個接口,當然這個接口是沒有任何方法的,直接implements就好,類似于這種沒有任何方法的接口被稱為標記接口.

二.知識點介紹

1、概念

2、序列化

3、序列化流

4、對象反序列化流

5、將用戶信息存儲到文件中與讀取文件用戶

6、序列化接口

7、瞬態(tài)關(guān)鍵字transient

三.上課視頻對應(yīng)說明文檔

1、序列化流概念

序列化流可以將對象進行序列化和反序列化。

用于從流中讀取對象的操作流 ObjectInputStream稱為反序列化流

用于向流中寫入對象的操作流 ObjectOutputStream稱為序列化流

注意:對象序列化時,對象的數(shù)據(jù)類型定義時一定要實現(xiàn)Serializable接口,從而實現(xiàn)可持久化。

2、序列化

對象的壽命通常隨著生成該對象的程序的終止而終止,有時候需要把在內(nèi)存中的各種對象的狀態(tài)(也就是實例變量,不是方法)保存下來,并且可以在需要時再將對象恢復(fù)。雖然你可以用你自己的各種各樣的方法來保存對象的狀態(tài),但是Java給你提供一種應(yīng)該比你自己的好的保存對象狀態(tài)的機制,那就是序列化。

總結(jié):Java 序列化技術(shù)可以使你將一個對象的狀態(tài)寫入一個Byte 流里(系列化),并且可以從其它地方把該Byte 流里的數(shù)據(jù)讀出來(反序列化)。

2.1、序列化的用途

(1)想把的內(nèi)存中的對象狀態(tài)保存到一個文件中或者數(shù)據(jù)庫中時候

(2)想把對象通過網(wǎng)絡(luò)進行傳播的時候

2.2、序列化的實現(xiàn)

實現(xiàn)Serializable接口

3、序列化流

將一個對象以對象的形式存儲到文件中。

ObjectOutputStream writeObject():寫出對象

代碼示例:

public class ObjectStreamDemo {

public static void main(String[] args) throws IOException, ClassNotFoundException {

/*

* 將一個對象存儲到持久化(硬盤)的設(shè)備上。

*/

writeObj();//對象的序列化。

}

public static void writeObj() throws IOException {

//1,明確存儲對象的文件。

FileOutputStream fos = new FileOutputStream("aa\\obj.txt");

//2,給操作文件對象加入寫入對象功能。

ObjectOutputStream oos = new ObjectOutputStream(fos);

//3,調(diào)用了寫入對象的方法。

oos.writeObject(new Person("wangcai",20));

//關(guān)閉資源。

oos.close();

}

}

4、對象反序列化流

當把一個對象持久化存儲起來之后,需要使用反序列化技術(shù)獲取存儲起來的對象

ObjectInputStream readObject():讀取對象。使用此ObjectInputStream對象就可以完成反序列化動作

代碼示例:

public class ObjectStreamDemo {

public static void main(String[] args)throws IOException, ClassNotFoundException {

readObj();//對象的反序列化。

}

public static void readObj() throws IOException, ClassNotFoundException {

//1,定義流對象關(guān)聯(lián)存儲了對象文件。

FileInputStream fis = new FileInputStream("aa\\obj.txt");

//2,建立用于讀取對象的功能對象。

ObjectInputStream ois = new ObjectInputStream(fis);

Person obj = (Person)ois.readObject();

System.out.println(obj.toString());

}

}

5、將用戶信息存儲到文件中與讀取文件用戶

5.1、用戶實體類

代碼示例:

import java.io.Serializable;

/*

*

* Serializable 接口

* 作用: 想要序列化,就必須實現(xiàn)這個 接口. 不用重寫任何方法.? 只是標記 一下.

*/

public class User? implements Serializable{

String name ;

String psw ;

int age;

public User() {

super();

}

public User(String name, String psw) {

super();

this.name = name;

this.psw = psw;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getPsw() {

return psw;

}

public void setPsw(String psw) {

this.psw = psw;

}

@Override

public String toString() {

return "User [name=" + name + ", psw=" + psw + "]";

}

@Override

public int hashCode() {

final int prime = 31;

int result = 1;

result = prime * result + ((name == null) ? 0 : name.hashCode());

result = prime * result + ((psw == null) ? 0 : psw.hashCode());

return result;

}

@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj == null)

return false;

if (getClass() != obj.getClass())

return false;

User other = (User) obj;

if (name == null) {

if (other.name != null)

return false;

} else if (!name.equals(other.name))

return false;

if (psw == null) {

if (other.psw != null)

return false;

} else if (!psw.equals(other.psw))

return false;

return true;

}

}

5.2、序列化存儲

代碼示例:

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectOutputStream;

/*

*? 序列化和反序列化?

*? 序列化: 從內(nèi)存保存到硬盤?

*? 反序列化 : 從硬盤讀取到內(nèi)存 .

*? 操作的數(shù)據(jù)都是對象 .? 都是Object

*?

*/

public class Demo {

public static void main(String[] args) throws IOException {

// 創(chuàng)建序列化 流對象?

ObjectOutputStream oos? = new ObjectOutputStream(new FileOutputStream("user.txt"));

User user = new User("老王", "laowang");//java.io.NotSerializableException: cn.javahelp_02.User

oos.writeObject(user);

oos.close();

}

}

5.3、反序列化讀取

代碼示例:

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.ObjectInputStream;

/*

* 讀取序列化的信息, 反序列化.?

*/

public class Demo2 {

public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {

// 創(chuàng)建反序列化 流 .

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.txt"));

Object obj = ois.readObject();

System.out.println(obj);

if (obj instanceof User) {

User u = (User) obj;

String name = u.getName();

System.out.println(name);

}

ois.close();

}

}

在創(chuàng)建對象讀?。▓笞x取文件結(jié)尾異常)思考:不知道里面存儲多少元素,但是讀到結(jié)尾就報異常,這樣怎么辦。

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.ObjectInputStream;

/*

* 讀取序列化的信息, 反序列化.?

*/

public class Demo2 {

public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {

// 創(chuàng)建反序列化 流 .

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.txt"));

Object obj = ois.readObject();

System.out.println(obj);

if (obj instanceof User) {

User u = (User) obj;

String name = u.getName();

System.out.println(name);

}

Object obj2 = ois.readObject(); //End Of File? Exception? 讀取文件結(jié)尾異常

System.out.println(obj2);

ois.close();

}

}

5.4、集合序列化解決不知道存儲元素數(shù)問題

代碼示例:

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.util.ArrayList;

/*

*? 把集合序列化.?

*/

public class Demo3 {

public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {

ArrayList<User > arrayList = new ArrayList<>();

User user = new User("金蓮","jinlian");

User user2 = new User("西門","daguanren");

User user3 = new User("大郎","cuibing");

arrayList.add(user);

arrayList.add(user2);

arrayList.add(user3);

//創(chuàng)建 序列化流

ObjectOutputStream oos? = new? ObjectOutputStream(new FileOutputStream("user2.txt"));

oos.writeObject(arrayList);

oos.close();

ObjectInputStream ois? = new ObjectInputStream(new FileInputStream("user2.txt"));

Object readObject = ois.readObject();

System.out.println(readObject);

// 強制 轉(zhuǎn)換? 在遍歷? readObject? --> ArrayList<User>

ArrayList<User>? userList? = (ArrayList<User>) readObject;

for (User u : userList) {

System.out.println(u.getName() +" -- "+ u.getPsw());

}

}

}

6、序列化接口

當一個對象要能被序列化,這個對象所屬的類必須實現(xiàn)Serializable接口。否則會發(fā)生異常NotSerializableException異常。

同時當反序列化對象時,如果對象所屬的class文件在序列化之后進行了修改,那么進行反序列化也會發(fā)生異常InvalidClassException。發(fā)生這個異常的原因如下:

該類的序列版本號與從流中讀取的類描述符的版本號不匹配

該類包含未知數(shù)據(jù)類型

該類沒有可訪問的無參數(shù)構(gòu)造方法

Serializable標記接口。該接口給需要序列化的類,提供了一個序列版本號。 serialVersionUID. 該版本號的目的在于驗證序列化的對象和對應(yīng)類是否版本匹配。

標記作用,當年的類沒變,雖然添加了屬性,但是可以

代碼示例:

public class Person implements Serializable {

/*

*? serialVersionUID = 1L

*? 只是一個對象的標記. 防止 你的類升級了, 對象 與類的信息 不一致.

*/

//給類顯示聲明一個序列版本號。

private static final long serialVersionUID = 1L;

private String name;

private int age;

public Person() {

super();

}

public Person(String name, int age) {

super();

this.name = name;

this.age = age;

}

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;

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + "]";

}

}

7、瞬態(tài)關(guān)鍵字transient

當一個類的對象需要被序列化時,某些屬性不需要被序列化,這時不需要序列化的屬性可以使用關(guān)鍵字transient修飾。只要被transient修飾了,序列化時這個屬性就不會被序列化了。

同時靜態(tài)修飾也不會被序列化,因為序列化是把對象數(shù)據(jù)進行持久化存儲,而靜態(tài)的屬于類加載時的數(shù)據(jù),不會被序列化。

代碼示例:

public class Person implements Serializable {

/*

* 給類顯示聲明一個序列版本號。

*

*只要被transient修飾了,序列化時這個屬性就不會琲序列化了。不想保存

*/

private static final long serialVersionUID = 1L;

private static String name;

private transient/*瞬態(tài)*/ int age;

public Person() {

super();

}

public Person(String name, int age) {

super();

this.name = name;

this.age = age;

}

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;

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + "]";

}

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容