最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳細說一說Java序列化的幾種方式對比

 更新時間:2025年07月05日 11:52:01   作者:程序員小假  
在某種情況下需要考慮一些安全問題和數(shù)據(jù)對象的使用問題,這時候就可以用序列化的技術(shù)來進行數(shù)據(jù)存儲,這篇文章主要介紹了Java序列化幾種方式對比的相關(guān)資料,需要的朋友可以參考下

what

什么是序列化

首先要明白,序列化它是一個過程,什么過程呢?

把一個java對象轉(zhuǎn)化成字節(jié)序列的過程

java對象都知道,那什么是字節(jié)序列呢?

字節(jié),也就是byte,1byte = 8bit,也就是一個字節(jié)等于8位,每一位都是用0或者1來表示,在內(nèi)存中,數(shù)據(jù)就是以二進制的形式存儲的
那序列呢?簡單看來說就好比排隊,一列一列的,至此,字節(jié)序列,是不是就是像字節(jié)在排隊一樣,而字節(jié)又是一個個的8bit,理解了吧!
所以,Java中的序列化就是把Java對象變成二進制內(nèi)容的一個過程,也就是從內(nèi)存中把數(shù)據(jù)存儲下來,而數(shù)據(jù)在內(nèi)存中都是二進制的形式!
記住了,Java序列化出來的東西就是一個二進制內(nèi)容,就是對象在內(nèi)存中的存儲形式! 

變量存儲角度理解序列化

接下來再以變量在內(nèi)存中的存儲為例去理解什么是序列化!

舉一個例子,比如寫一個變量:

String name = "張三";

也就是剛開始,把name的值設(shè)置成為”張三“,在后面的程序當中,可以修改這個name,比如又把name的值修改成為”李四“!
程序的運行,需要把數(shù)據(jù)加載進內(nèi)存才可以,也就是說,無論是最開始的”張三“還是后來的”李四“都會被加載進內(nèi)存運行,那內(nèi)存都會為這些變量分配內(nèi)存!

可是,一旦程序執(zhí)行完畢,變量所分配或者說所占用的內(nèi)存就會被回收, 程序也就結(jié)束了,不過在這個過程中,可以從內(nèi)存中把這些變量存儲下來,那這個過程就叫做序列化! 

反序列化

當理解了什么是序列化之后,那反序列化也就不是問題了,自然而然的就懂了,所謂的反序列化用稍微專業(yè)點的話說就是:
把字節(jié)序列還原成對象的過程

由此可見,無論序列化還是反序列化,都是對象和字節(jié)序列之間的互相轉(zhuǎn)換! 

序列化的多樣性

以上得知,序列化是一個對象和字節(jié)序列互相轉(zhuǎn)換的過程,那隨之而來的一個問題就是,該怎么轉(zhuǎn)換?

也就是該如何實現(xiàn)把對象序列化成字節(jié)序列,然后再把字節(jié)序列反序列化成對象,這其中必然存在一種規(guī)則,序列化和反序列化都必須按照這個規(guī)則來!

那這個規(guī)則就是序列化協(xié)議,那由此基本可以得出,可能存在不同的序列化協(xié)議,然后有不同的方式去實現(xiàn)序列化。

也就是不管怎么處理,最終實現(xiàn)的目的是對象和字節(jié)序列的互相轉(zhuǎn)換即可,比如Java就有其自己實現(xiàn)的一套序列化機制,可以把Java對象序列化成字節(jié)序列,還可以把自己序列再通過反序列化還原成原來的對象!

除了Java,像熟知的json也有其自己的序列化技術(shù),加入用Java的序列化技術(shù)把一個對象序列化成了字節(jié)序列,那用json的反序列化技術(shù)是無法將其還原成原本的Java對象的! 

how

Java序列化demo演示

比如定義一個簡單的Person類,包含以下簡單屬性:

private String name;
private int age;

接著就可以將其序列化,具體操作如下:

FileOutputStream outputStream = new FileOutputStream("C:\\Users\\ithuangqing\\desktop\\person.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
Person person = new Person();
person.setName("張三");
person.setAge(25);
objectOutputStream.writeObject(person);
objectOutputStream.flush();
objectOutputStream.close();

以上就是在Java中的序列化過程,執(zhí)行該程序 ,會在桌面生成一個person.txt的文本文件,查看下內(nèi)容,發(fā)現(xiàn)是亂碼:

可以使用專業(yè)的十六進制編輯器查看,可以看到相關(guān)的十六進制內(nèi)容以及二進制內(nèi)容,這個就是Java對象序列化后的字節(jié)序列了。
接著看看如何將其反序列化,也就是將其還原成原來的 Java 對象!

//反序列化
Person person = null;
File file;
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\ithuangqing\\desktop\\person.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
person = (Person) objectInputStream.readObject();
objectInputStream.close();
fileInputStream.close();
System.out.println(person.getName());

可以得到相應(yīng)的結(jié)果,執(zhí)行上述反序列化程序,可以得出:

正確得到之前設(shè)置的name,說明反序列化成功,以上就是在Java中的序列化和反序列化操作! 

查看序列化出來的內(nèi)容

可以查看序列化出來的字節(jié)序,會發(fā)現(xiàn)以txt文本形式查看是一些亂碼,亂七八糟的,也看不懂,可以以二進制內(nèi)容查看!

這些二進制內(nèi)容,就是該Peroson對象在內(nèi)存中的存儲形式!這也是Java把對象序列化出來的二進制內(nèi)容! 

序列化條件Serializable

一個Java對象要想實現(xiàn)序列化的功能,那就必須實現(xiàn)一個接口,如下:

可以查看該接口的定義:

可以發(fā)現(xiàn),這就是一個空接口,在Java中這樣的接口叫做“標記接口”英文叫做Marker Interface,一般來說,一個類如果實現(xiàn)了一個標記接口,起到的作用僅僅是給自己增加一個標簽,比如上述這個,如果一個類實現(xiàn)了這個接口,那就會給自己身增加一個“序列化”的標簽,說明這個類可以實現(xiàn)序列化相關(guān)功能! 

為什么要實現(xiàn)Serializable接口

那為什么要實現(xiàn)Serializable接口呢難道就是為了讓其實現(xiàn)序列化?說起來好像是這么回事,但是還是有一些深入的內(nèi)容需要了解的!
首先來看兩個類:

1、ObjectOutputStream

2、ObjectInputStream

兩個類:經(jīng)過之前的代碼演示清楚了,對于Java的序列化而言就是通過上述兩個數(shù)據(jù)流類來完成的,也就是說他們包含了序列化和反序列化對象的方法,分別如下:

 先拿ObjectOutputStream來說,這個類包含很多寫方法來寫各種的數(shù)據(jù)類型,舉一個例子來看:

可以看到其中包含一個writeInt方法可以將基本數(shù)據(jù)類型寫到外部文件中,同樣的則可以使用ObjectInputStream 再將外部的數(shù)據(jù)讀取進來:

查看打印輸出:

所以對于 ObjectInputStream 和 ObjectOutputStream這種高層次的數(shù)據(jù)流來說,它可以完成這樣的一些操作,就是可以通過寫操作將數(shù)據(jù)類型轉(zhuǎn)換為字節(jié)流,而讀操作又可以將字節(jié)流轉(zhuǎn)換成特定的數(shù)據(jù)類型!

那對于Java這種高級面向?qū)ο缶幊陶Z言而言,對象則是Java中所有數(shù)據(jù)的一個類型載體,因此也要可以對對象進行相應(yīng)的讀寫,說白了就是需要讓Java虛擬機知道在進行IO操作的時候,如何進行對象和字節(jié)流之間的轉(zhuǎn)換,而Serializable接口就起到了這樣的作用!

所以對于ObjectInputStream 和 ObjectOutputStream來說最主要的作用是進行Java序列化的操作,主要是因為他們提供了如下的兩個方法:

1、序列化一個對象

public final void writeObject(Object x) throws IOException

2、反序列化對象

public final Object readObject() throws IOException, ClassNotFoundException

.ser文件

可以看這里的一步操作:

也就是把Java對象序列化出來的字節(jié)序列內(nèi)容存儲到了一個txt文本文件里面,不過,就好比寫的與i寫純文本文件的格式txt,寫的Java文件格式是java,也就是后綴名是.java,所以這里序列化出來的文件也有一個標準的格式叫做.ser
那為什么叫做這個呢?因為Java中要把一個對象序列化需要實現(xiàn)Serializable,看這個單詞的開頭,操作一下:

執(zhí)行該序列化程序,會得到該文件:

可以打開看下:

以二進制內(nèi)容查看:

和之前的txt的內(nèi)容是一致的!說這個只是希望大家后續(xù)在見到.ser文件知道這是一個序列化文件! 

再看序列化是什么

到了這里再來看看,什么是Java的序列化:

把Java對象在內(nèi)存中的狀態(tài)給存儲下來的一個過程,會得到一個該Java對象的字節(jié)序列,可以說是一個二進制內(nèi)容,本質(zhì)上是一個byte[]數(shù)組!

為什么說是byte[]數(shù)組呢?1byte = 8bit,也就是8位一組,也就是一個字節(jié),而二進制內(nèi)存都是0和1這種8位8位的,看下:

看著這張圖,可以理解為什么是byte[]數(shù)組了吧! 

why

序列化可以用在哪些地方

經(jīng)過之前的描述知道了,通過序列化,可以把Java對象轉(zhuǎn)換成字節(jié)序列,也就是二進制內(nèi)容,這個內(nèi)容中就包含了對象的相關(guān)數(shù)據(jù),以及對象的類型信息和存儲在對象中的數(shù)據(jù)的類型!

也就是說,通過反序列化是可以還原這個Java對象的,而且這個過程是Java虛擬機來操作的,是直接由Java虛擬機來構(gòu)建這個對象,所以這個對象中的構(gòu)造函數(shù)是不會得到執(zhí)行的,因為根本不會經(jīng)過這一步,虛擬機直接把對象給整出來了!

那就知道了,反序列化是由虛擬機來搞定的,那么也就是實現(xiàn)了,在一個平臺上序列化出來的對象,完全可以放到另一個平臺上去反序列化該對象!

因此,這就造成了,序列化可以用于一些特定的數(shù)據(jù)傳輸:

1、把內(nèi)存中的對象保存起來,比如保存到數(shù)據(jù)庫中或者保存到一個文件中,以便長期保存

2、使用socket進行網(wǎng)絡(luò)數(shù)據(jù)傳輸

3、RMI(即遠程調(diào)用Remote Method Invocation)的使用,也就是要利用對象序列化去運行遠程主機上的服務(wù),以達到就像在本地機上運行對象時一樣。 

序列化有哪些好處

那序列化有什么好處呢?或者說為什么要用序列化呢?

首先,數(shù)據(jù)其實是比較復(fù)雜的,比如對象啊,文件啊,等等都有各自不同的數(shù)據(jù)格式,怎么能把它們統(tǒng)一保存呢?這不,序列化就可以啊,經(jīng)過序列化之后,別管是什么,都保存在一塊了,都是字節(jié)序列,這就方便數(shù)據(jù)之間的傳輸了,因為格式統(tǒng)一!

另外,序列化保存的是對象在內(nèi)存中的保存狀態(tài),反序列化的時候是由Java虛擬機直接將該類還原在內(nèi)存中,簡潔快速而高效!

還有就是有的時候需要把Java對象從內(nèi)存中保存下來,以便脫離內(nèi)存,存儲在磁盤上,達到長期保存的目的,那這個序列化就很合適了! 

序列化注意事項

異常

這里主要有兩個異常:

1、ClassNotFoundException:沒有找到對應(yīng)的Class

2、InvalidClassException:Class不匹配

首先說一下第一個異常,也就是ClassNotFoundException,這個其實是比較簡單的,也就是類沒找到,什么類沒找到呢?代碼復(fù)現(xiàn)一下:

2021-08-30-22-35-55-328432.png

執(zhí)行該代碼,就會發(fā)生問題:

2021-08-30-22-35-55-553430.png

這個錯誤其實已經(jīng)說的很明顯了,沒有找到Person這個類了,那是因為把之前的Person改成Person1了,所以反序列化就找不到對應(yīng)的類,這就是無法實現(xiàn)反序列化的:

2021-08-30-22-35-55-718433.png

再把Person1改回Person試一下:

2021-08-30-22-35-55-932435.png

也就是反序列化的時候,得有個對應(yīng)的類,而且這個類的路徑位置啥的也是不能改變的:

2021-08-30-22-35-56-149431.png

接下來看下InvalidClassException這個也就是Class不匹配的問題。
同樣,通過代碼來演示:

2021-08-30-22-35-56-345435.png

為什么會出現(xiàn)這個錯誤呢?看這里:

2021-08-30-22-35-56-447434.png

之前是int,反序列化的時候這成了long,不就是不匹配嘛,所以這樣也是會出錯的!
所以啊,總的來說,就是,序列化的時候是什么樣子的,反序列化個一模一樣的,但是如果就沒有定義這樣的一個類,那反序列化肯定就出錯了! 

如何解決:serialVersionUID

為了解決InvalidClassException的問題,就出現(xiàn)了這么一個東西,先看代碼:

這個操作大家應(yīng)該不陌生吧,應(yīng)該都見過的,它的出現(xiàn)主要就是為了解決Class類型不匹配的問題,它作為標識Java類的序列化版本,可以看作是一個標記,一般來說,可以由IDE自動生成,如果修改了類中的字段什么的,那這個serialVersionUID就會發(fā)生改變,通過這樣的一種機制來自動阻止不匹配的class版本!

在之前進行序列化操作的時候并沒有創(chuàng)建這個serialVersionUID,但是,沒有顯式創(chuàng)建就并不代表它沒有,而是會生成默認的serialVersionUID,但是,在實際當中,Java官方建議還是要顯式的創(chuàng)建serialVersionUID!

為啥,因為如果不顯式創(chuàng)建,那么默認的生成時高度依賴于JVM的,但是如果序列化和反序列化是跨平臺操作的化,就有可能會發(fā)生前后創(chuàng)建的serialVersionUID不一致從而導(dǎo)致反序列化出現(xiàn)異常,所以還是要顯式創(chuàng)建serialVersionUID,保證即使跨平臺這個serialVersionUID也是一致的!

serialVersionUID是如何起作用的呢?

說的簡單點就是,序列化的時候這個serialVersionUID也被序列化進去了,那在反序列化的時候,JVM就會把傳進來的字節(jié)流中的serialVersionUID與本地對應(yīng)的類中的serialVersionUID進行比較,看是否一致,一致就可以反序列化,不一致就不能反序列化,看代碼演示:

這里顯式創(chuàng)建serialVersionUID,然后進行序列化操作生成新的字節(jié)序列內(nèi)容,在反序列化之前,把這個serialVersionUID給修改下:

然后進行反序列化操作:

產(chǎn)生異常了,看來是類不匹配,看下這個異常描述:

說的是不是很清楚了!

那這個時候,再次將起修改成1L,然后做如下操作:

那根據(jù)之前說的,這里修改了類,那反序列化的化就會出現(xiàn)InvalidClassException 問題,那執(zhí)行反序列化看下:

果然報錯,類型問題,不過再來看一個情況:

再反序列化試下:

正常輸出,沒有報錯,但是如果沒有顯式自定義serialVersionUID的話,那就會由系統(tǒng)自定義生成,那就會報錯了!

所以一定要注意serialVersionUID的加與不加的一些區(qū)別和可能會產(chǎn)生的問題!也就是說序列化完成之后,如果原類型字段增加或者減少,不指定serialVersionUID的情況下,也是會報不一致的錯誤。指定了則不報錯! 

Java的序列化安全嘛

以上較為詳細的介紹了Java的序列化操作,那么現(xiàn)在來思考這樣的一個問題,Java的序列化安全嘛?也就是使用Java序列化的操作會不會產(chǎn)生什么安全隱患?

想象一下這個,就是,序列化生成的字節(jié)序列可以通過反序列化直接將其在內(nèi)存中還原成原狀態(tài),那如果某個字節(jié)序列是特意設(shè)置好的,含有一些不安全代碼,那直接給還原到內(nèi)存中了,是不是會產(chǎn)生一些安全問題!

所以Java中提供的序列化機制,本身是存在一些安全性問題的,那更好的辦法是啥呢?可以通過使用json來實現(xiàn),這樣輸出的數(shù)據(jù)都是一些基本類型的內(nèi)容,不像Java序列化那樣,序列化輸出的包含了很多對象相關(guān)信息!

總結(jié)

到此這篇關(guān)于Java序列化幾種方式對比的文章就介紹到這了,更多相關(guān)Java序列化幾種方式對比內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JVM 命令行工具的使用

    JVM 命令行工具的使用

    造成Java應(yīng)用出現(xiàn)性能問題的因素非常多,想要定位這些問題,一款優(yōu)秀的性能診斷工具必不可少,本文主要介紹了JVM 命令行工具的使用,具有一定的參考價值,感興趣的可以了解一下
    2024-04-04
  • java圖片色階調(diào)整和亮度調(diào)整代碼示例

    java圖片色階調(diào)整和亮度調(diào)整代碼示例

    這篇文章主要介紹了java圖片色階調(diào)整和亮度調(diào)整代碼示例,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • Java中綴表達式轉(zhuǎn)后綴表達式實現(xiàn)方法詳解

    Java中綴表達式轉(zhuǎn)后綴表達式實現(xiàn)方法詳解

    這篇文章主要介紹了Java中綴表達式轉(zhuǎn)后綴表達式實現(xiàn)方法,結(jié)合實例形式分析了Java中綴表達式轉(zhuǎn)換成后綴表達式的相關(guān)算法原理與具體實現(xiàn)技巧,需要的朋友可以參考下
    2019-03-03
  • IDEA Ultimate2020.2版本配置Tomcat詳細教程

    IDEA Ultimate2020.2版本配置Tomcat詳細教程

    這篇文章主要介紹了IDEA Ultimate2020.2版本配置Tomcat教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • java 模仿拼多多紅包遞減算法的實現(xiàn)

    java 模仿拼多多紅包遞減算法的實現(xiàn)

    這篇文章主要介紹了java 模仿拼多多紅包遞減算法的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • 如何設(shè)置Spring Boot測試時的日志級別

    如何設(shè)置Spring Boot測試時的日志級別

    Spring Boot是由Pivotal團隊提供的全新框架,其設(shè)計目的是用來簡化新Spring應(yīng)用的初始搭建以及開發(fā)過程。該框架使用了特定的方式來進行配置,從而使開發(fā)人員不再需要定義樣板化的配置。下面我們來一起學習一下吧
    2019-06-06
  • 解決springmvc整合Mybatis的Log4j日志輸出問題

    解決springmvc整合Mybatis的Log4j日志輸出問題

    這篇文章主要介紹了解決springmvc整合Mybatis的Log4j日志輸出問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • mybatis中數(shù)據(jù)加密與解密的實現(xiàn)

    mybatis中數(shù)據(jù)加密與解密的實現(xiàn)

    數(shù)據(jù)加解密的實現(xiàn)方式多種多樣,在mybatis環(huán)境中數(shù)據(jù)加解密變得非常簡單易用,本文主要介紹了mybatis中數(shù)據(jù)加密與解密的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Java線程池execute()方法源碼全面解析

    Java線程池execute()方法源碼全面解析

    這篇文章主要介紹了Java線程池execute()方法源碼全面解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • java的io操作(將字符串寫入到txt文件中)

    java的io操作(將字符串寫入到txt文件中)

    這篇文章主要介紹了java的io操作示例,將字符串寫入到txt文件中,需要的朋友可以參考下
    2014-04-04

最新評論

启东市| 昌黎县| 呼图壁县| 隆昌县| 大关县| 南宁市| 刚察县| 马关县| 永福县| 象山县| 乌兰浩特市| 连云港市| 广德县| 赤峰市| 英吉沙县| 广南县| 谷城县| 天门市| 冀州市| 六盘水市| 潮安县| 抚顺县| 康定县| 九江市| 蓝田县| 平邑县| 敦煌市| 凌源市| 徐闻县| 读书| 昌宁县| 德惠市| 衡东县| 富锦市| 六盘水市| 辽阳市| 从化市| 平罗县| 泊头市| 浙江省| 枞阳县|