Java 序列化詳解及簡(jiǎn)單實(shí)現(xiàn)實(shí)例
一、序列化
序列化定義:序列化是將對(duì)象狀態(tài)轉(zhuǎn)換為可保持或傳輸?shù)母袷降倪^程。與序列化相對(duì)的是反序列化,它將流轉(zhuǎn)換為對(duì)象。這兩個(gè)過程結(jié)合起來,可以輕松地存儲(chǔ)和傳輸數(shù)據(jù)。
目的:
- 以某種存儲(chǔ)形式使自定義對(duì)象持久化
- 將對(duì)象從一個(gè)地方傳遞到另一個(gè)地方
二、Java序列化
一個(gè)對(duì)象能夠序列化的前提是實(shí)現(xiàn)Serializable接口。Serializable接口沒有方法,更像是個(gè)標(biāo)記。有了這個(gè)標(biāo)記的Class就能被序列化機(jī)制處理。如下:
class myPoint implements Serializable{
}
JAVA反序列化不會(huì)調(diào)用任何構(gòu)造器
序列化的控制:Externalizable。讀寫都交給你
- 要在方法writeExternal寫入序列化的參數(shù)
- 要在方法readExternal讀取反序列化的值
- 要有默認(rèn)的構(gòu)造方法(readExternal執(zhí)行完成,再執(zhí)行默認(rèn)的構(gòu)造器)
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException,ClassNotFoundException;
public class Point implements Externalizable {
private int a;
private int b;
public Point(int a, int b) {
this.a = a;
this.b = b;
}
public Point() {
}
public String toString() {
return a + " , " + b;
}
public void writeExternal(ObjectOutput out) throws IOException {
out.write(a);
out.write(b);
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
a = in.read();
b = in.read();
}
public static void main(String[] args) throws IOException,
ClassNotFoundException {
String file = "d://1.txt";
Point p = new Point(1, 2);
System.out.println(p);
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p);
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Point pp = (Point) ois.readObject();
System.out.println(pp);
}
}
- transient關(guān)鍵字 關(guān)閉序列化自動(dòng)進(jìn)行。
- 不管你選擇了哪種序列化形式,都要為自己編寫的每個(gè)可序列化的類聲明一個(gè)顯示的序列版本UID(serial version UID)
三、序列化的問題
在effective Java中列舉出了java序列化要注意的一些問題:
1.謹(jǐn)慎地設(shè)計(jì)實(shí)現(xiàn)Serializable接口
- 實(shí)現(xiàn)發(fā)布了就是一種承諾
- 如果一個(gè)類是為繼承設(shè)計(jì)的,在‘允許子類實(shí)現(xiàn)Serializable接口'與‘禁止子類實(shí)現(xiàn)Serializable接口'取一個(gè)折中的方案是:提供一個(gè)可訪問的無參構(gòu)造器
2.保護(hù)性地編寫 readObject()方法,因?yàn)閞eadObject()是構(gòu)建實(shí)例的入口。
不保護(hù)可能出現(xiàn) 構(gòu)建了不滿足要求的 實(shí)例
3.考慮自定義的序列化形式
- 邏輯內(nèi)容 與 物理表示法
- 如果一個(gè)對(duì)象的 ‘物理表示法'等同于它的‘邏輯內(nèi)容',可能就適用于使用默認(rèn)的序列化形式。
- 如果有更好的 ‘物理表示法'在表示‘邏輯內(nèi)容'則可以自定義序列化形式。
public class StringList implements Serializable {
private transient int size = 0;
private transient Entity head = null;
public final void add(String str) {
// ...
}
private static class Entity {
String data;
Entity next;
Entity previous;
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.write(size);
for (Entity e = head; e != null; e = e.next) {
s.writeObject(e.data);
}
}
private void readObject(ObjectInputStream s) throws IOException,
ClassNotFoundException {
s.defaultReadObject();
int num = s.read();
for (int i = 0; i < num; i++) {
this.add((String) s.readObject());
}
}
}
四、序列化代理模式
序列化機(jī)制提供的鉤子函數(shù)有:
writeReplace writeObject readObject readResolve
- writeReplace:序列化的時(shí)候替換所要序列化的對(duì)象。
- writeObject:寫入序列化的對(duì)象
- readObject:讀取序列化的對(duì)象
- readResolve:最后返回序列化對(duì)象
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.Date;
public final class Period implements Serializable {
private static final long serialVersionUID = 100L;
private final Date start;
private final Date end;
public Period(Date start, Date end) {
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
if (this.start.compareTo(this.end) > 0) {
throw new IllegalArgumentException(start + " after " + end);
}
}
public Date start() {
return new Date(start.getTime());
}
public Date end() {
return new Date(end.getTime());
}
public String toString() {
return start + " - " + end;
}
// 不給
private Object writeReplace() {
return new SerializationProxy(this);
}
private void readObject(ObjectInputStream stream)
throws InvalidObjectException {
throw new InvalidObjectException("proxy request");
}
private static class SerializationProxy implements Serializable {
private final Date start;
private final Date end;
SerializationProxy(Period p) {
this.start = p.start;
this.end = p.end;
}
private Object readResolve() {
return new Period(start, end);
}
private static final long serialVersionUID = 1000L;
}
}
五、序列化算法
- 將對(duì)象實(shí)例相關(guān)的類元數(shù)據(jù)輸出。
- 遞歸地輸出類的超類描述直到不再有超類。
- 類元數(shù)據(jù)完了以后,開始從最頂層的超類開始輸出對(duì)象實(shí)例的實(shí)際數(shù)據(jù)值。
- 從上至下遞歸輸出實(shí)例的數(shù)據(jù)
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
springboot項(xiàng)目啟動(dòng)的時(shí)候參數(shù)無效的解決
這篇文章主要介紹了springboot項(xiàng)目啟動(dòng)的時(shí)候參數(shù)無效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
springboot中如何通過cors協(xié)議解決跨域問題
這篇文章主要介紹了springboot中通過cors協(xié)議解決跨域問題,cors是一個(gè)w3c標(biāo)準(zhǔn),它允許瀏覽器(目前ie8以下還不能被支持)像我們不同源的服務(wù)器發(fā)出xmlHttpRequest請(qǐng)求,我們可以繼續(xù)使用ajax進(jìn)行請(qǐng)求訪問。具體內(nèi)容詳情大家跟隨腳本之家小編一起學(xué)習(xí)吧2018-05-05
Spring框架事務(wù)屬性中事務(wù)隔離級(jí)別與傳播行為全面講解
這篇文章主要介紹了Spring框架聲明式事務(wù)的事務(wù)隔離級(jí)別和事務(wù)傳播行為,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-11-11
Spring4下validation數(shù)據(jù)校驗(yàn)無效(maven)的解決
這篇文章主要介紹了Spring4下validation數(shù)據(jù)校驗(yàn)無效(maven)的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Java線程池的幾種實(shí)現(xiàn)方法和區(qū)別介紹實(shí)例詳解
本篇文章主要介紹了Java線程池的幾種實(shí)現(xiàn)方法和區(qū)別,需要的朋友可以參考2017-04-04
Spring Boot Logging Level設(shè)置為off時(shí)的Bug
這篇文章主要介紹了Spring Boot Logging Level設(shè)置為off時(shí)的Bug,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09

