1恨统、基本介紹
1.對象的序列化:將Object類型的對象轉(zhuǎn)換成byte序列挺益,簡單來講就是要存儲對象,將對象寫入文件卵酪。
序列化流(ObjectOutputStream),核心方法writeObject()
2.對象的反序列化:將byte序列轉(zhuǎn)換成Object類型的對象,簡單來講就是從文件中讀取對象凛澎。
反序列化流(ObjectInputStream)霹肝,核心方法readObject()
3.序列化接口:對象必須實現(xiàn)序列化接口(Serializable),才能進(jìn)行序列化塑煎,否則將出現(xiàn)異常沫换。該接口中沒有任何方法,只是一個標(biāo)準(zhǔn)最铁。
注意:
當(dāng)一個類實現(xiàn)了序列化接口讯赏,其子類都可以實現(xiàn)序列化;
對子類對象實現(xiàn)反序列化操作時冷尉,如果其父類沒有實現(xiàn)序列化接口漱挎,那么其父類的構(gòu)造方法會被調(diào)用,不會進(jìn)行反序列化雀哨。
2磕谅、實現(xiàn)對象的序列化——寫入對象
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
// 創(chuàng)建Student類并實現(xiàn)Serializable接口,準(zhǔn)備將該類的對象寫入文件
class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class Demo1 {
public static void main(String[] args) throws IOException {
fun1();
}
public static void fun1() throws IOException {
/*
* 根據(jù)其構(gòu)造方法
* ObjectOutputStream(OutputStream out)
* 傳入的參數(shù)是OutputStream類型的
* 因為多態(tài)的存在
* 所以O(shè)utputStream類的子類類型都可以
*/
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f:\\Demo1.txt"));
Student s1 = new Person("Tom", 20);
oos.writeObject(s1);
oos.close();
}
}
3雾棺、實現(xiàn)對象的反序列化——讀取對象
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException, IOException {
fun2();
}
public static void fun2() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("f:\\Demo1.txt"));
// 直接向下強(qiáng)制轉(zhuǎn)型為Student類
/*
* 注意readObject()方法會拋出兩個異常:
* IOException,ClassNotFoundException
* 之所以會有ClassNotFoundException
* 是因為對象是依賴于其所屬類的字節(jié)碼文件(類名.class)的
* 因此在讀取對象時膊夹,
* 必須要求其所屬類的字節(jié)碼文件也存在
*/
Student obj = (Student) ois.readObject();
System.out.println(obj.getName() + "," + obj.getAge());
ois.close();
}
}
4、Serializable接口
1.序列號:
在寫入對象時捌浩,對象所屬的類實現(xiàn)的Serializable接口會在該類內(nèi)部同時寫入一個唯一的UID序列號放刨,以便找到該類;如果在寫入對象完成之后尸饺,修改了該類中的任意內(nèi)容进统,那么序列號也會隨之改變柿估,會導(dǎo)致找不到該類策州,從而引發(fā)異常。因此在處理對象的序列化時窿给,建議聲明自己的UID馋辈,例如:
static final long serialVersionUID = 42L;
這樣不論該類內(nèi)部怎樣發(fā)生變化抚芦,都不會改變序列號。
2.transient:
例如對象在網(wǎng)絡(luò)中傳輸也需要實現(xiàn)序列化迈螟,但如果希望某個元素不在網(wǎng)絡(luò)中傳輸以節(jié)省流量叉抡,即不參與默認(rèn)的序列化過程,可將其修飾為:
private transient int age;
這樣Student類對象的年齡屬性就不會被存儲答毫,從而實現(xiàn)了不參與序列化褥民,最終返回的是該屬性的默認(rèn)值。
但不參與虛擬機(jī)默認(rèn)的序列化不代表不能被序列化洗搂,可以手動實現(xiàn)參與序列化過程消返,將readObject()方法和writeObject()方法的方法簽名添加到對應(yīng)類中载弄,代碼如下:
class Student implements Serializable {
private String name;//可以默認(rèn)進(jìn)行序列化
private transient int age;//需要手動實現(xiàn)序列化
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
//添加writeObject()的方法簽名
private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException{
s.defaultWriteObject();//將可以默認(rèn)實現(xiàn)序列化的元素進(jìn)行序列化操作
s.writeObject(age);//手動實現(xiàn)age的序列化
}
//添加readObject()的方法簽名
private void readObject(java.io.ObjectInputStream s)throws java.io.IOException,ClassNotFoundException{
s.defaultReadObject();//將可以默認(rèn)實現(xiàn)反序列化的元素進(jìn)行反序列化操作
this.age = (int) s.readObject();//手動實現(xiàn)age的反序列化操作
}
}
實現(xiàn)手動控制某些元素是否參與序列化過程,目的是為了提高程序運(yùn)行的性能撵颊,可以參考ArrayList的原碼宇攻,在其定義的數(shù)組上修飾了transient,并不是不進(jìn)行序列化倡勇,而是手動實現(xiàn)對有效數(shù)據(jù)進(jìn)行序列化逞刷,反序列化同理,因此提高了程序的性能妻熊。
版權(quán)聲明:歡迎轉(zhuǎn)載夸浅,歡迎擴(kuò)散,但轉(zhuǎn)載時請標(biāo)明作者以及原文出處扔役,謝謝合作帆喇! ↓↓↓