摘要:引語平時我們在運行程序的時候創建的對象都在內存中當程序停止或者中斷了對象也就不復存在了如果我們能將對象保存起來在需要使用它的時候在拿出來使用就好了并且對象的信息要和我們保存時的信息一致序列化就可以解決了這樣的問題序列化當然不止一種方式如下序
引語:
????平時我們在運行程序的時候,創建的對象都在內存中,當程序停止或者中斷了,對象也就不復存在了.如果我們能將對象保存起來,在需要使用它的時候在拿出來使用就好了,并且對象的信息要和我們保存
時的信息一致.序列化就可以解決了這樣的問題.序列化當然不止一種方式,如下:
序列類型 | 是否跨語言 | 優缺點 |
---|---|---|
hession | 支持 | 跨語言,序列化后體積小,速度較快 |
protostuff | 支持 | 跨語言,序列化后體積小,速度快,但是需要Schema,可以動態生成 |
jackson | 支持 | 跨語言,序列化后體積小,速度較快,且具有不確定性 |
fastjson | 支持 | 跨語言支持較困難,序列化后體積小,速度較快,只支持java,c# |
kryo | 支持 | 跨語言支持較困難,序列化后體積小,速度較快 |
fst | 不支持 | 跨語言支持較困難,序列化后體積小,速度較快,兼容jdk |
jdk | 不支持 | 序列化后體積很大,速度快 |
我們今天介紹的就是java原生的Serializable序列化.
先列一下概念:
序列化:序列化是將對象的狀態信息轉換為可以存儲或傳輸的形式的過程
反序列化:從存儲或傳輸形式還原為對象
序列化使用起來很簡單只需要實現Serializable接口即可,然后序列化(序列化是將對象的狀態信息轉換為可以存儲或傳輸的形式的過程)和反序列化(反之,從存儲或傳輸形式還原為對象).
只要使用ObjectOutputStream和ObjectInputStream將對象轉為二進制序列和還原為java對象.話不多說,看下代碼示例:
private static void testSerializable(String fileName) throws IOException { try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(fileName))) { // "XXX" 的String也可以直接作為對象進行反序列化的 objectOutputStream.writeObject("test serializable"); SerializableData data = new SerializableData(1, "testStr"); objectOutputStream.writeObject(data); } } private static void testDeserializable(String fileName) throws IOException, ClassNotFoundException { try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(fileName))) { String str = (String) objectInputStream.readObject(); System.out.println("String的反序列化: " + str); SerializableData readData = (SerializableData) objectInputStream.readObject(); System.out.println("反序列化的對象: " + readData.toString()); // 輸出:反序列化的對象: SerializableData(testInt=1, testStr=testStr) } } // 使用到的類 @Data @AllArgsConstructor class SerializableData implements Serializable { private Integer testInt; private String testStr; }
第一個方法是傳入文件路徑,將String和SerializableData對象序列化到fileName指定的文件中;第二個方法是反序列化將文件中的二進制還原為java對象.
這里其實比較簡單沒有什么大問題,稍微提一句的就是writeObject這個方法是可以直接將"寫入的字符串"這種形式的對象直接序列化為二進制的.
這里還有一點就是反序列化的版本號必須和原本對象的版本號(private static final long serialVersionUID = 1L;這個因為是自己測試所以沒有寫默認是1L,修改后,反序列化的對象版本號不一致會報錯)一致,并且jvm能找到反序列化的文件的位置,否則都會失敗.
簡單的使用序列化和反序列化應該沒有什么問題,我們再來看看transient關鍵字是啥?在某些場景下,我們需要寫入或者還原的數據中其實有我們不需要透露或者說不想暴露給外部的數據,如果我們將這些隱私的數據序列化,在反序列化出來,
那么這些信息就泄漏了.而transient關鍵字呢,就是防止這種事情的發生.
當屬性被加上了transient關鍵字以后,序列化時不會將該屬性的值給寫入,所以反序列化的時候我們會發現原本寫入的數據,還原出來是null.
我們寫一個例子看看是否是這樣呢?
private static void testTransient() throws IOException, ClassNotFoundException { String fileName = "transientData.txt"; try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName))) { Account data = new Account(1, "user1", "123456"); out.writeObject(data); } try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) { Account readData = (Account) in.readObject(); System.out.println("transient關鍵字的對象: " + readData.toString()); // 輸出: transient關鍵字的對象: Account(id=1, userName=user1, idCardNumber=null) } } // 對應的對象 @Data @AllArgsConstructor class Account implements Serializable { private Integer id; private String userName; private transient String idCardNumber; }
這里我們有一個Account對象,我們不想暴露出我們的省份證號碼idCardNumber,于是乎加上了transient關鍵字.
然后將idCardNumber已經初始化過的data對象序列化,當我們再反序列化去取得這個idCardNumber的值的時候,發現確實對象的idCardNumber是null,transient是起作用的.
如果是對基本類型數據加上transitent話,會得到對應的默認值,就好比是int的數據類型,得到的就是0.
使用過自動的序列化和反序列化以后,我們又想在序列化和反序列化的時候我們能不能自己控制呢?在序列化和反序列化的時候我們能不能加點日志或者其他的操作之類的呢?
是的,闊以的.只需要輕輕一點,實現Externalizable接口即可,和Serializable使用差不多.
private static void testExternalizable() throws IOException, ClassNotFoundException { String fileName = "testExternalizable.txt"; try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName))) { Account2 data = new Account2("user1", 1); out.writeObject(data); } try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) { Account2 readData = (Account2) in.readObject(); System.out.println("Externalizable的對象: " + readData.toString()); } } // 使用到的對象 @Data @AllArgsConstructor class Account2 implements Externalizable { private Integer id; private String userName; private transient String idCardNumber; @Override public void writeExternal(ObjectOutput out) throws IOException { System.out.println("執行了writeExternal方法"); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { System.out.println("執行了readExternal方法"); } }
如果執行了上面的代碼,恭喜你,獲得一個Exception的獎勵.大概長這樣,java.io.InvalidClassException:XXX no valid constructor,
Externalizable在執行的時候會調用默認的無參構造函數,而且記住哦,必須是public的,如果沒有加public你會發現又獎勵了一個Exception給你.
講道理這個是比較坑的.下面我們來看看正確的用法,序列化和反序列化都是我們自己控制的:
private static void testExternalizable() throws IOException, ClassNotFoundException { String fileName = "testExternalizable.txt"; try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName))) { Account3 data = new Account3("user1", 1); out.writeObject(data); } try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName))) { Account3 readData = (Account3) in.readObject(); System.out.println("Externalizable的對象: " + readData.toString()); /** * 輸出: * 執行了writeExternal方法 * 執行了readExternal方法 * Externalizable的對象: Account3(userName=user1, id=1) */ } } @ToString class Account3 implements Externalizable { private String userName; private Integer id; public Account3() { } public Account3(String userName, Integer id) { this.userName = userName; this.id = id; } @Override public void writeExternal(ObjectOutput out) throws IOException { System.out.println("執行了writeExternal方法"); out.writeObject(userName); out.writeInt(id); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { System.out.println("執行了readExternal方法"); userName = (String) in.readObject(); id = in.readInt(); } }總結:
1.我們介紹了jdk自帶的序列化和反序列化(和其中的一些坑點);
2.知道了transient可以將隱私數據不序列化;
3.還有Externalizable可以自己來控制序列化和反序列化的進程.
1.https://docs.oracle.com/javas...
2.https://blog.csdn.net/do_bset...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75523.html
摘要:從的序列化和反序列化說起序列化是將對象的狀態信息轉換為可以存儲或傳輸的形式的過程,而相反的過程就稱為反序列化。當使用接口來進行序列化與反序列化的時候需要開發人員重寫與方法。 從java的序列化和反序列化說起 序列化 (Serialization)是將對象的狀態信息轉換為可以存儲或傳輸的形式的過程,而相反的過程就稱為反序列化。 在java中允許我們創建可復用的對象,但是這些對象僅僅存在j...
摘要:序列化對象和平臺無關,序列化得到的字節流可以在任何平臺反序列化。從文件中或網絡上獲得序列化的字節流后,根據字節流中所保存的對象狀態及描述信息,通過反序列化重建對象。因此意味著不要序列化靜態變量不屬于對象狀態的一部分,因此它不參與序列化。 一.序列化和反序列化(1)序列化:將內存中的對象轉化為字節序列,用于持久化到磁盤中或者通過網絡傳輸。對象序列化的最主要的用處就是傳遞和保存對象,保證對...
摘要:序列化反序列化主要體現在程序這個過程中,包括網絡和磁盤。如果是開發應用,一般這兩個注解對應的就是序列化和反序列化的操作。協議的處理過程,字節流內部對象,就涉及這兩種序列化。進行第二步操作,也就是序列化和反序列化的核心是。 以下內容,如有問題,煩請指出,謝謝! 對象的序列化/反序列化大家應該都比較熟悉:序列化就是將object轉化為可以傳輸的二進制,反序列化就是將二進制轉化為程序內部的...
摘要:把字節序列恢復為對象的過程稱為對象的反序列化。代表對象輸入流,它的方法從一個源輸入流中讀取字節序列,再把它們反序列化為一個對象,并將其返回。接口繼承自接口,實現接口的類完全由自身來控制序列化的行為,而僅實現接口的類可以采用默認的序列化方式。 把對象轉換為字節序列的過程稱為對象的序列化。把字節序列恢復為對象的過程稱為對象的反序列化。 對象的序列化主要有兩種用途: 1) 把...
摘要:虛擬機讀取其他進程的數據對象的方法可以運行平臺上的其他程序該方法產生一個對象對象代表由該程序啟動啟動的子進程類提供如下三個方法用于和其子進程通信獲取子進程的錯誤流獲取子進程的輸入流獲取子進程的輸出流這里的輸入流輸出流容易混淆從程序的角度思考 Java虛擬機讀取其他進程的數據 Runtime對象的exec方法可以運行平臺上的其他程序,該方法產生一個Process對象,Process對象...
閱讀 2742·2021-11-24 10:23
閱讀 1153·2021-11-17 09:33
閱讀 2503·2021-09-28 09:41
閱讀 1409·2021-09-22 15:55
閱讀 3641·2019-08-29 16:32
閱讀 1903·2019-08-29 16:25
閱讀 1056·2019-08-29 11:06
閱讀 3421·2019-08-29 10:55