Java中序列化與反序列化的定義及代碼示例
序列化與反序列化的定義
序列化(Serialization)與反序列化(Deserialization)是編程中常見的兩個(gè)概念,它們主要涉及到將數(shù)據(jù)結(jié)構(gòu)或?qū)ο鬆顟B(tài)轉(zhuǎn)換為可以存儲(chǔ)或傳輸?shù)母袷?,以及將存?chǔ)或傳輸?shù)母袷睫D(zhuǎn)換回原始的數(shù)據(jù)結(jié)構(gòu)或?qū)ο鬆顟B(tài)的過程。
這兩個(gè)過程在數(shù)據(jù)持久化、網(wǎng)絡(luò)通信、對(duì)象深拷貝等多個(gè)場(chǎng)景中發(fā)揮著重要作用。
序列化(Serialization)
序列化是指將數(shù)據(jù)結(jié)構(gòu)或?qū)ο鬆顟B(tài)轉(zhuǎn)換成可以存儲(chǔ)或傳輸?shù)母袷降倪^程。這個(gè)格式通常是平臺(tái)無關(guān)的,比如JSON、XML、二進(jìn)制格式等,以便可以在不同的系統(tǒng)或環(huán)境中進(jìn)行交換。序列化后的數(shù)據(jù)可以存儲(chǔ)在文件中,或者通過網(wǎng)絡(luò)發(fā)送給其他系統(tǒng)。
為什么需要序列化?
- 數(shù)據(jù)持久化:將對(duì)象狀態(tài)保存到文件中,以便在程序關(guān)閉或系統(tǒng)重啟后能夠重新加載這些數(shù)據(jù)。
- 網(wǎng)絡(luò)傳輸:在網(wǎng)絡(luò)通信中,數(shù)據(jù)需要在客戶端和服務(wù)器之間傳輸,序列化可以將對(duì)象轉(zhuǎn)換成字節(jié)流,便于在網(wǎng)絡(luò)上傳輸。
- 對(duì)象深拷貝:通過序列化一個(gè)對(duì)象,然后立即進(jìn)行反序列化,可以實(shí)現(xiàn)對(duì)象的深拷貝。
反序列化(Deserialization)
反序列化是序列化的逆過程,即將序列化后的數(shù)據(jù)(如JSON、XML、二進(jìn)制格式等)轉(zhuǎn)換回原始的數(shù)據(jù)結(jié)構(gòu)或?qū)ο鬆顟B(tài)。這個(gè)過程允許程序在需要時(shí)重新構(gòu)建對(duì)象,并使用其原始數(shù)據(jù)。
為什么需要反序列化?
- 數(shù)據(jù)恢復(fù):在程序啟動(dòng)時(shí),從文件中讀取序列化后的數(shù)據(jù),反序列化成對(duì)象,以恢復(fù)程序運(yùn)行前的狀態(tài)。
- 數(shù)據(jù)接收:在網(wǎng)絡(luò)通信中,接收到的序列化數(shù)據(jù)需要被反序列化成對(duì)象,以便在本地系統(tǒng)中使用。
Java的序列化
Java序列化是指將Java對(duì)象的狀態(tài)轉(zhuǎn)換為可以保存或傳輸?shù)母袷降倪^程。Java提供了多種序列化方式,以滿足不同的需求和場(chǎng)景。以下是Java序列化的幾種主要方式:
1. 實(shí)現(xiàn)Serializable接口
- 特點(diǎn):這是Java默認(rèn)的序列化方式,通過實(shí)現(xiàn)java.io.Serializable接口來標(biāo)記一個(gè)類可以被序列化。這種序列化方式是隱式的,會(huì)自動(dòng)序列化所有非static和transient關(guān)鍵字修飾的成員變量。
- 使用場(chǎng)景:適用于大多數(shù)需要序列化的場(chǎng)景,特別是當(dāng)對(duì)象的狀態(tài)需要被持久化或在網(wǎng)絡(luò)間傳輸時(shí)。
2. 實(shí)現(xiàn)Externalizable接口
- 特點(diǎn):與Serializable接口類似,但Externalizable接口提供了更高的靈活性。實(shí)現(xiàn)該接口的類必須手動(dòng)實(shí)現(xiàn)writeExternal()和readExternal()方法,以控制序列化和反序列化的過程。
- 使用場(chǎng)景:適用于需要精確控制序列化過程的場(chǎng)景,比如只序列化對(duì)象的某些部分,或者需要對(duì)序列化數(shù)據(jù)進(jìn)行加密等。
3. 使用JSON序列化庫
- 常用庫:如Jackson、Gson等。
- 特點(diǎn):將對(duì)象轉(zhuǎn)換為JSON格式的字符串進(jìn)行序列化,可以跨語言、跨平臺(tái)進(jìn)行數(shù)據(jù)交換。JSON格式易于閱讀和編寫,也易于機(jī)器解析和生成。
- 使用場(chǎng)景:適用于需要與其他語言或系統(tǒng)交互的場(chǎng)景,或者當(dāng)對(duì)象需要被存儲(chǔ)為文本格式時(shí)。
4. 使用XML序列化庫
- 常用庫:如JAXB、XStream等。
- 特點(diǎn):將對(duì)象轉(zhuǎn)換為XML格式的字符串進(jìn)行序列化,同樣可以跨語言、跨平臺(tái)進(jìn)行數(shù)據(jù)交換。XML格式具有良好的可擴(kuò)展性和可讀性。
- 使用場(chǎng)景:適用于需要遵循特定XML標(biāo)準(zhǔn)的場(chǎng)景,或者當(dāng)對(duì)象需要被存儲(chǔ)為易于人類閱讀的格式時(shí)。
5. 使用二進(jìn)制序列化庫
- 常用庫:如Protocol Buffers(protobuf)、Apache Thrift、Apache Avro等。
- 特點(diǎn):將對(duì)象序列化為二進(jìn)制格式進(jìn)行傳輸和存儲(chǔ),效率較高。這些庫通常提供了豐富的數(shù)據(jù)結(jié)構(gòu)和高效的編碼解碼算法。
- 使用場(chǎng)景:適用于對(duì)性能要求較高的場(chǎng)景,比如需要頻繁序列化和反序列化大量數(shù)據(jù)的系統(tǒng)。
6. 其他序列化方式
- Hessian序列化:Hessian是一種通過網(wǎng)絡(luò)傳輸和存儲(chǔ)Java對(duì)象的二進(jìn)制格式,可以跨語言、跨平臺(tái)使用,效率較高。
- Kryo序列化:Kryo是一種高性能的Java序列化庫,序列化和反序列化速度都很快,但只能用于Java環(huán)境。
Java提供了多種序列化方式,每種方式都有其特點(diǎn)和適用場(chǎng)景。在實(shí)際應(yīng)用中,可以根據(jù)具體需求和場(chǎng)景選擇合適的方式進(jìn)行Java對(duì)象的序列化。需要注意的是,除了Java默認(rèn)的序列化方式外,其他方式通常需要引入相應(yīng)的第三方庫。
Java默認(rèn)序列化與反序列化示例
我們先將一些Java的變量和一個(gè)Car對(duì)象序列化到 d盤的一個(gè)名為 data.dat 的文件中。
/** * ObjectOutputStream 的使用,完成數(shù)據(jù)的序列化 * ObjectOutputStream 是序列化 */ public class ObjectOutputStreamDemo { public static void main(String[] args) throws IOException { //序列化后,保存到文本格式不是純文本txt,而是按照它的格式來保存 String filePath = "d:\\data.dat"; ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath)); oos.writeInt(100);//int -> Integer(實(shí)現(xiàn)了Serializable) oos.writeBoolean(true);//boolean -> Boolean(實(shí)現(xiàn)了 Serializable) oos.writeChar('o');//char -> Character(實(shí)現(xiàn)了Serializable) oos.writeDouble(4.4);//double -> Double(實(shí)現(xiàn)了 Serializable) oos.writeUTF("對(duì)象輸出流");//String (實(shí)現(xiàn)了Serializable) oos.writeObject(new Car("xiaomi su7","Pro","Gulf Blue","300,000")); oos.close(); System.out.println("數(shù)據(jù)以序列化的形式保存完成"); /* 如果Car沒有實(shí)現(xiàn) Serializable接口,會(huì)報(bào)錯(cuò)如下: Exception in thread "main" java.io.NotSerializableException: org.example.io.demo.lession20.Car at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) at org.example.io.demo.lession20.ObjectOutputStreamDemo.main(ObjectOutputStreamDemo.java:24) */ } } @Data class Car implements Serializable { private String name; private String type; private static String color ; private transient String price ; public Car(String name,String type,String color,String price){ this.name = name; this.type = type; this.color = color; this.price = price; } }
執(zhí)行main方法后,會(huì)在d盤根目錄下看到一個(gè) data.dat的文件。
使用記事本打開,依稀可以看到點(diǎn)什么,但明顯不是txt格式的文本。
下面我們將這個(gè)文件反序列化至程序中并打印出來:
/** * 讀取序列化文件,并通過反序列化恢復(fù)數(shù)據(jù) * ObjectInputStream 是反序列化 */ public class ObjectInputStreamDemo { public static void main(String[] args) throws IOException, ClassNotFoundException { //指定反序列化的文件 String filePath = "d:\\data.dat"; ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath)); //讀取(即反序列化)的順序需要和保存數(shù)據(jù)(即序列化)的順序一致,否則會(huì)有異常 System.out.println(ois.readInt()); System.out.println(ois.readBoolean()); System.out.println(ois.readChar()); System.out.println(ois.readDouble()); System.out.println(ois.readUTF()); System.out.println(ois.readObject().toString()); ois.close(); } }
輸出結(jié)果為:
100
true
o
4.4
對(duì)象輸出流
Car(name=xiaomi su7, type=Pro, price=null)
Java 序列化與反序列化注意事項(xiàng):
- 讀寫順序要一致。
- 序列化與反序列化對(duì)象要實(shí)現(xiàn) Serializable 接口。
- 序列化中的類中,建議添加SerialVersionUID,為了提高版本的兼容性。
- 序列化對(duì)象時(shí),默認(rèn)將里面所有的屬性都進(jìn)行序列化,除了stati、transient 修飾的成員。
- 序列化對(duì)象時(shí),要求里面屬性的類型也需要實(shí)現(xiàn)序列化接口。
- 序列化具備可繼承性,也就是如果某類已經(jīng)實(shí)現(xiàn)了序列化,則它的所有子類也默認(rèn)實(shí)現(xiàn)了序列化。
TIPS:static 和 transient 在序列化中的區(qū)別
static關(guān)鍵字
- 定義:static關(guān)鍵字用于修飾類的成員變量和方法,使其成為類變量或類方法,而不是實(shí)例變量或?qū)嵗椒?。類變量屬于類本身,而非類的任何特定?shí)例。
- 序列化行為:在序列化過程中,被static修飾的變量(即類變量)不會(huì)被序列化。這是因?yàn)閟tatic變量是類級(jí)別的,它們不屬于任何特定的對(duì)象實(shí)例,而是由所有實(shí)例共享。因此,序列化一個(gè)對(duì)象時(shí),不會(huì)包含其類變量的值,因?yàn)轭愖兞康闹翟贘VM中是全局的,與特定的序列化實(shí)例無關(guān)。
- 反序列化影響:反序列化一個(gè)對(duì)象時(shí),被static修飾的變量會(huì)保持其在JVM中的當(dāng)前值,而不是從序列化數(shù)據(jù)中恢復(fù)。這是因?yàn)殪o態(tài)變量是全局的,不受單個(gè)對(duì)象實(shí)例的序列化/反序列化過程影響。
transient關(guān)鍵字
- 定義:transient關(guān)鍵字用于修飾類的成員變量,以指示該變量在序列化時(shí)不應(yīng)被序列化。
- 序列化行為:當(dāng)一個(gè)對(duì)象被序列化時(shí),所有非transient修飾的成員變量都會(huì)被序列化,而transient修飾的變量則會(huì)被忽略。這意味著,在序列化后的數(shù)據(jù)中,不會(huì)包含任何被transient修飾的變量的值。
- 反序列化影響:在反序列化過程中,被transient修飾的變量將不會(huì)被恢復(fù)其序列化前的值。相反,它們會(huì)被初始化為默認(rèn)值(例如,數(shù)值類型的變量會(huì)被初始化為0或false,對(duì)象類型的變量會(huì)被初始化為null)。因此,開發(fā)者需要在反序列化后,根據(jù)需要手動(dòng)為這些變量賦值。
二者對(duì)比表格
關(guān)鍵字 | 定義 | 序列化行為 | 反序列化影響 |
---|---|---|---|
static | 修飾類變量或類方法,屬于類本身 | 不被序列化 | 保持JVM中的當(dāng)前值 |
transient | 修飾成員變量,指示在序列化時(shí)忽略該變量 | 被忽略,不被序列化 | 被初始化為默認(rèn)值 |
總結(jié)
到此這篇關(guān)于Java中序列化與反序列化的文章就介紹到這了,更多相關(guān)Java序列化與反序列化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中Scanner的常用方法總結(jié)(一次學(xué)懂)
這篇文章主要給大家介紹了關(guān)于Java中Scanner常用方法的相關(guān)資料,Java中的Scanner是一個(gè)用于讀取用戶輸入的類,它可以讀取各種類型的數(shù)據(jù),包括整數(shù)、浮點(diǎn)數(shù)、字符串等等,需要的朋友可以參考下2023-11-11SpringBoot如何使用mail實(shí)現(xiàn)登錄郵箱驗(yàn)證
在實(shí)際的開發(fā)當(dāng)中,不少的場(chǎng)景中需要我們使用更加安全的認(rèn)證方式,同時(shí)也為了防止一些用戶惡意注冊(cè),我們可能會(huì)需要用戶使用一些可以證明個(gè)人身份的注冊(cè)方式,如短信驗(yàn)證、郵箱驗(yàn)證等,這篇文章主要介紹了SpringBoot如何使用mail實(shí)現(xiàn)登錄郵箱驗(yàn)證,需要的朋友可以參考下2024-06-06java多線程Thread的實(shí)現(xiàn)方法代碼詳解
這篇文章主要介紹了java多線程Thread的實(shí)現(xiàn)方法代碼詳解,涉及start(),run(),stop(),interrupt(),isInterrupted(),join()和join(long millis)等方法的介紹,具有一定借鑒價(jià)值,需要的朋友可以了解下。2017-11-11SpringBoot集成Shiro進(jìn)行權(quán)限控制和管理的示例
這篇文章主要介紹了SpringBoot集成Shiro進(jìn)行權(quán)限控制和管理的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03解決springboot遇到autowire注入為null的問題
這篇文章主要介紹了解決springboot遇到autowire注入為null的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-03-03Eclipse創(chuàng)建JavaWeb工程的完整步驟記錄
很多新手不知道Eclipse怎么創(chuàng)建Java Web項(xiàng)目,一起來看看吧,這篇文章主要給大家介紹了關(guān)于Eclipse創(chuàng)建JavaWeb工程的完整步驟,需要的朋友可以參考下2023-10-10Java超詳細(xì)教你寫一個(gè)網(wǎng)絡(luò)購書系統(tǒng)案例
這篇文章主要介紹了怎么用Java來寫一個(gè)購書系統(tǒng),購買書籍主要需要每本書的編號(hào)、書名、單價(jià)、庫存屬性,能夠讓客戶通過編號(hào)來選書,感興趣的朋友跟隨文章往下看看吧2022-03-03idea如何在service窗口中顯示多個(gè)服務(wù)
這篇文章主要介紹了idea如何在service窗口中顯示多個(gè)服務(wù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09如何基于SpringMVC實(shí)現(xiàn)斷點(diǎn)續(xù)傳(HTTP)
這篇文章主要介紹了如何基于SpringMVC實(shí)現(xiàn)斷點(diǎn)續(xù)傳(HTTP),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01