Java 序列化詳解及簡單實現(xiàn)實例
一、序列化
序列化定義:序列化是將對象狀態(tài)轉換為可保持或傳輸?shù)母袷降倪^程。與序列化相對的是反序列化,它將流轉換為對象。這兩個過程結合起來,可以輕松地存儲和傳輸數(shù)據(jù)。
目的:
- 以某種存儲形式使自定義對象持久化
- 將對象從一個地方傳遞到另一個地方
二、Java序列化
一個對象能夠序列化的前提是實現(xiàn)Serializable接口。Serializable接口沒有方法,更像是個標記。有了這個標記的Class就能被序列化機制處理。如下:
class myPoint implements Serializable{ }
JAVA反序列化不會調(diào)用任何構造器
序列化的控制:Externalizable。讀寫都交給你
- 要在方法writeExternal寫入序列化的參數(shù)
- 要在方法readExternal讀取反序列化的值
- 要有默認的構造方法(readExternal執(zhí)行完成,再執(zhí)行默認的構造器)
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關鍵字 關閉序列化自動進行。
- 不管你選擇了哪種序列化形式,都要為自己編寫的每個可序列化的類聲明一個顯示的序列版本UID(serial version UID)
三、序列化的問題
在effective Java中列舉出了java序列化要注意的一些問題:
1.謹慎地設計實現(xiàn)Serializable接口
- 實現(xiàn)發(fā)布了就是一種承諾
- 如果一個類是為繼承設計的,在‘允許子類實現(xiàn)Serializable接口'與‘禁止子類實現(xiàn)Serializable接口'取一個折中的方案是:提供一個可訪問的無參構造器
2.保護性地編寫 readObject()方法,因為readObject()是構建實例的入口。
不保護可能出現(xiàn) 構建了不滿足要求的 實例
3.考慮自定義的序列化形式
- 邏輯內(nèi)容 與 物理表示法
- 如果一個對象的 ‘物理表示法'等同于它的‘邏輯內(nèi)容',可能就適用于使用默認的序列化形式。
- 如果有更好的 ‘物理表示法'在表示‘邏輯內(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()); } } }
四、序列化代理模式
序列化機制提供的鉤子函數(shù)有:
writeReplace writeObject readObject readResolve
- writeReplace:序列化的時候替換所要序列化的對象。
- writeObject:寫入序列化的對象
- readObject:讀取序列化的對象
- readResolve:最后返回序列化對象
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; } }
五、序列化算法
- 將對象實例相關的類元數(shù)據(jù)輸出。
- 遞歸地輸出類的超類描述直到不再有超類。
- 類元數(shù)據(jù)完了以后,開始從最頂層的超類開始輸出對象實例的實際數(shù)據(jù)值。
- 從上至下遞歸輸出實例的數(shù)據(jù)
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關文章
springboot中如何通過cors協(xié)議解決跨域問題
這篇文章主要介紹了springboot中通過cors協(xié)議解決跨域問題,cors是一個w3c標準,它允許瀏覽器(目前ie8以下還不能被支持)像我們不同源的服務器發(fā)出xmlHttpRequest請求,我們可以繼續(xù)使用ajax進行請求訪問。具體內(nèi)容詳情大家跟隨腳本之家小編一起學習吧2018-05-05Spring4下validation數(shù)據(jù)校驗無效(maven)的解決
這篇文章主要介紹了Spring4下validation數(shù)據(jù)校驗無效(maven)的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06Java線程池的幾種實現(xiàn)方法和區(qū)別介紹實例詳解
本篇文章主要介紹了Java線程池的幾種實現(xiàn)方法和區(qū)別,需要的朋友可以參考2017-04-04Spring Boot Logging Level設置為off時的Bug
這篇文章主要介紹了Spring Boot Logging Level設置為off時的Bug,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09