一.介紹
序列化流:把對象按照流一樣的方式存入文本文件或者在網(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 + "]";
}
}