Java序列化原理詳解
前言
關(guān)于序列化的幾種疑問?
- 什么是序列化?工作中什么時(shí)候用到序列化了?
- 為什么實(shí)現(xiàn)了java.io.Serializable接口就能序列化?
- java中serialVersionUID 為什么不能改變?
- Serializable序列化和json序列化有什么關(guān)系?
- 你都會(huì)哪幾種對(duì)象深拷貝方式?
以上拋出了幾個(gè)問題,大家都能回答上來嗎?回答不上來的話就接著往下看吧。
前提知識(shí):
講解之前先擴(kuò)充一些前提知識(shí)。
二進(jìn)制協(xié)議和文本協(xié)議
首先我們要知道所有的數(shù)據(jù)在底層的傳輸都是二進(jìn)制流,這點(diǎn)是毋庸置疑的。
那什么是文本協(xié)議?什么是二進(jìn)制協(xié)議呢?
文本協(xié)議
文本協(xié)議一般是由一串ACSII字符組成的數(shù)據(jù),這些字符包括數(shù)字,大小寫字母、百分號(hào),還有回車(\r),換行(\n)以及空格等等。
文本協(xié)議設(shè)計(jì)的目的就是方便人們理解、讀懂,所以,協(xié)議中通常會(huì)加入一些特殊字符用于分隔。
比如日常中發(fā)送請(qǐng)求時(shí)經(jīng)常用到的方式: xml
, json
, formData
,他們雖然格式不同,但都有一個(gè)特征,自帶描述信息。
formData 31bytes
account=sqrtcat&password=123456
json 41bytes
{"account":"sqrtcat","password":"123456"}
xml 94bytes
<?xml version="1.0" encoding="UTF-8" ?> <account>sqrtcat</account> <password>123456</password>
但為了便于解析,文本協(xié)議不得不添加一些冗余的字符用于分隔命令,降低了其傳輸?shù)男?;而且只適于傳輸文本,很難嵌入其他數(shù)據(jù),比如一張圖片。
二進(jìn)制協(xié)議
二進(jìn)制協(xié)議就是一串字節(jié)流,通常包括消息頭(header)和消息體(body),消息頭的長(zhǎng)度固定,并且消息頭包括了消息體的長(zhǎng)度。這樣就能夠從數(shù)據(jù)流中解析出一個(gè)完整的二進(jìn)制數(shù)據(jù)。
二進(jìn)制協(xié)議,沒有冗余字段,傳輸高效,方便解析(固定長(zhǎng)度,并且可以直接比較字節(jié)),缺點(diǎn)就是定義的比較死,哪個(gè)位置有哪些東西,是什么意義是定義死的,場(chǎng)景單一。
序列化
首先讓百度來解釋一下什么是序列化:
序列化 是將對(duì)象的狀態(tài)信息轉(zhuǎn)換為可以存儲(chǔ)或傳輸?shù)男问降倪^程。在序列化期間,對(duì)象將其當(dāng)前狀態(tài)寫入到臨時(shí)或持久性存儲(chǔ)區(qū)。之后,可以通過從存儲(chǔ)區(qū)中讀取或反序列化對(duì)象的狀態(tài),重新創(chuàng)建該對(duì)象。
那我們工作中什么時(shí)候用到序列化了?
在創(chuàng)建一個(gè)Java類時(shí)實(shí)現(xiàn)java.io.Serializable接口,將你的對(duì)象進(jìn)行網(wǎng)絡(luò)傳輸或者持久化;
使用spring注解@ResponseBody或者使用JSON框架(jackson、Gson、fastjson)等給前端返回json數(shù)據(jù)。
以上都涉及到了序列化。
為什么實(shí)現(xiàn)了java.io.Serializable接口就能序列化?
Java自己提供了一種序列化機(jī)制,這種機(jī)制能將一個(gè)對(duì)象序列化成二進(jìn)制形式,用于寫入磁盤或輸出到網(wǎng)絡(luò),同時(shí)將從網(wǎng)絡(luò)或者磁盤中讀取的字節(jié)數(shù)組,反序列化成對(duì)象,在程序中使用。
便是實(shí)現(xiàn)java.io包下的Serializable接口,使用JDK 提供的兩個(gè)輸入、輸出流對(duì)象 ObjectInputStream 和 ObjectOutputStream便可以對(duì)java對(duì)象進(jìn)行序列化和反序列化。
java中serialVersionUID 不能改變的原因是避免反序列失敗,可能會(huì)拋出序列化運(yùn)行時(shí)異常。
Java序列化缺陷
實(shí)際工作中會(huì)發(fā)現(xiàn)我們自己很少會(huì)使用java提供的序列化,主要是因?yàn)镴DK默認(rèn)的序列化存在著一些非常嚴(yán)重的缺陷,比如它是無法實(shí)現(xiàn)跨平臺(tái)和跨語言的,意思是我們?cè)趈ava中序列化的對(duì)象是無法被其他語言或者是被瀏覽器反序列的。
為了解決這一問題通常將Java對(duì)象轉(zhuǎn)換為XML或Json格式進(jìn)而實(shí)現(xiàn)網(wǎng)絡(luò)傳輸。
JSON
看下定義:
JSON(JavaScript Object Notation, JS對(duì)象簡(jiǎn)譜)是一種輕量級(jí)的數(shù)據(jù)交換格式。它基于 ECMAScript(European Computer Manufacturers Association, 歐洲計(jì)算機(jī)協(xié)會(huì)制定的js規(guī)范)的一個(gè)子集,采用完全獨(dú)立于編程語言的文本格式來存儲(chǔ)和表示數(shù)據(jù)。簡(jiǎn)潔和清晰的層次結(jié)構(gòu)使得 JSON 成為理想的數(shù)據(jù)交換語言。 易于人閱讀和編寫,同時(shí)也易于機(jī)器解析和生成,并有效地提升網(wǎng)絡(luò)傳輸效率。它和xml一樣都是一種數(shù)據(jù)交換格式。
我們?cè)诤蠖藢⑿枰祷氐臄?shù)據(jù)通過json處理成json字符串后轉(zhuǎn)為二進(jìn)制在網(wǎng)絡(luò)中傳輸,瀏覽器會(huì)解析為json字符串,進(jìn)而我們可以再通過json將json字符串轉(zhuǎn)換為對(duì)象。
json 是?種很簡(jiǎn)潔的協(xié)議,但可惜的是,它只能傳遞基本的數(shù)型(int,long,string等),但不能傳遞byte類型。如果想要傳輸圖?等?進(jìn)制?件的話,是沒辦法直接傳輸。
json序列化在webapi項(xiàng)目中非常流行。因?yàn)閖son非常的直觀明了,調(diào)用者能夠很直觀的知道返回的數(shù)據(jù)信息。
二進(jìn)制序列化一般情況下數(shù)據(jù)大小會(huì)比xml,json的序列化的更小。但是二進(jìn)制則不能直觀的知道數(shù)據(jù)的內(nèi)容信息。
深拷貝
提供幾種Java對(duì)象深拷貝方案:
//1.構(gòu)造函數(shù) 《不推薦》 //2.implements Cloneable 重寫clone() 《不推薦》 //3.序列化后反序列化 《推薦》 // 使用Apache Commons Lang序列化進(jìn)行深拷貝 User copyUser = (User) SerializationUtils.clone(user); // 使用Gson序列化進(jìn)行深拷貝 Gson gson = new Gson(); User copyUser = gson.fromJson(gson.toJson(user), User.class); // 使用Jackson序列化進(jìn)行深拷貝 ObjectMapper objectMapper = new ObjectMapper(); User copyUser = objectMapper.readValue(objectMapper.writeValueAsString(user), User.class);
上面我們可以通過json序列化的方式進(jìn)行對(duì)象深拷貝,下面再提供一種使用二進(jìn)制序列化的方式進(jìn)行List<對(duì)象>深拷貝的實(shí)現(xiàn)方式:
public static <T> List<T> copyList(List<T> source) { try { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(source); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream inStream = new ObjectInputStream(byteIn); List<T> list = (List<T>) inStream.readObject(); inStream.close(); byteIn.close(); out.close(); byteOut.close(); return list; } catch (Exception e) { log.info(e.getMessage(), e); } return null; }
到此這篇關(guān)于Java序列化原理詳解的文章就介紹到這了,更多相關(guān)Java序列化 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring純注解開發(fā)模式讓開發(fā)簡(jiǎn)化更簡(jiǎn)化
Spring3.0引入了純注解開發(fā)的模式,框架的誕生是為了簡(jiǎn)化開發(fā),那注解開發(fā)就是簡(jiǎn)化再簡(jiǎn)化。Spring的特性在整合MyBatis方面體現(xiàn)的淋漓盡致哦2022-08-08Spring MVC項(xiàng)目中l(wèi)og4J和AOP使用詳解
項(xiàng)目日志記錄是項(xiàng)目開發(fā)、運(yùn)營(yíng)必不可少的內(nèi)容,有了它可以對(duì)系統(tǒng)有整體的把控,出現(xiàn)任何問題都有蹤跡可尋。下面這篇文章主要給大家介紹了關(guān)于Spring MVC項(xiàng)目中l(wèi)og4J和AOP使用的相關(guān)資料,需要的朋友可以參考下。2017-12-12Tomcat?8.5?+mysql?5.7+jdk1.8開發(fā)JavaSE的金牌榜小項(xiàng)目
這篇文章主要介紹了Tomcat?8.5?+mysql?5.7+jdk1.8開發(fā)JavaSE的金牌榜小項(xiàng)目,本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05SpringBoot整合JWT(JSON?Web?Token)生成token與驗(yàn)證的流程及示例
JSON Web Token(JWT)是一種開放的標(biāo)準(zhǔn)(RFC 7519),定義了一種緊湊的、自包含的方式來安全地在各方之間傳輸信息作為JSON對(duì)象,這篇文章主要給大家介紹了關(guān)于SpringBoot整合JWT(JSON?Web?Token)生成token與驗(yàn)證的相關(guān)資料,需要的朋友可以參考下2024-07-07springcloud?nacos動(dòng)態(tài)線程池Dynamic?tp配置接入實(shí)戰(zhàn)詳解
這篇文章主要為大家介紹了springcloud?nacos動(dòng)態(tài)線程池Dynamic?tp配置接入實(shí)戰(zhàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12idea項(xiàng)目實(shí)現(xiàn)移除和添加git
本文指導(dǎo)讀者如何從官網(wǎng)下載并安裝Git,以及在IDEA中配置Git的詳細(xì)步驟,首先,用戶需訪問Git官方網(wǎng)站下載適合自己操作系統(tǒng)的Git版本并完成安裝,接著,在IDEA中通過設(shè)置找到git.exe文件以配置Gi2024-10-10JAVA生成八位不重復(fù)隨機(jī)數(shù)最快的方法總結(jié)(省時(shí)間省空間)
隨機(jī)數(shù)在實(shí)際中使用很廣泛,比如要隨即生成一個(gè)固定長(zhǎng)度的字符串、數(shù)字,這篇文章主要給大家介紹了關(guān)于JAVA生成八位不重復(fù)隨機(jī)數(shù)最快的方法,文中介紹的方法省時(shí)間省空間,需要的朋友可以參考下2024-03-03