Effective Java之谨慎地实现Serializable(七十四)
1.序列化的含義和作用
序列化用來(lái)將對(duì)象編碼成字節(jié)流,反序列化就使將字節(jié)流編碼重新構(gòu)建對(duì)象。
序列化實(shí)現(xiàn)了對(duì)象傳輸和對(duì)象持久化,所以它能夠?yàn)檫h(yuǎn)程通信提供對(duì)象表示法,為JavaBean組件提供持久化數(shù)據(jù)。
2.序列化的危害
1.降低靈活性:為實(shí)現(xiàn)Serializable而付出的最大代價(jià)是,一旦一個(gè)類被發(fā)布,就大大降低了”改變這個(gè)類的實(shí)現(xiàn)”的靈活性。如果一個(gè)類實(shí)現(xiàn)了Serializable,它的字節(jié)流編碼(或者說(shuō)序列化形式,serialized form)就變成了它的導(dǎo)出的API的一部分,必須永遠(yuǎn)支持這種序列化形式。
而且,特殊地,每個(gè)可序列化類都有唯一的標(biāo)志(serial version id,在類體現(xiàn)為私有靜態(tài)final的long域serialVersionUID),如果沒(méi)有顯式指示,那么系統(tǒng)就會(huì)自動(dòng)生成一個(gè)serialVersionUID,如果下一個(gè)版本改變了這個(gè)類,那么系統(tǒng)就會(huì)重新自動(dòng)生成一個(gè)serialVersionUID。因此如果沒(méi)有聲明顯式的uid,會(huì)破壞版本之間的兼容性,運(yùn)行時(shí)產(chǎn)生InvalidClassException。
2.降低封裝性:如果你接受了默認(rèn)的序列化形式,這個(gè)類中私有的和包級(jí)私有的實(shí)例域?qū)⒍甲兂蓪?dǎo)出的API的一部分,這不符合”最低限度地訪問(wèn)域”的實(shí)踐準(zhǔn)則。
3.降低安全性:增加了bug和漏洞的可能性,反序列化的過(guò)程其實(shí)類似于調(diào)用對(duì)象的構(gòu)造器,但是這個(gè)過(guò)程又沒(méi)有用到構(gòu)造器,因此如果字節(jié)流被無(wú)意修改或被用心不測(cè)的人修改,那么服務(wù)器很可能會(huì)產(chǎn)生錯(cuò)誤或者遭到攻擊。
16年出現(xiàn)的大名鼎鼎的Java反序列化漏洞本質(zhì)上就是不恰當(dāng)?shù)男蛄谢斐傻摹?/p>
4.降低可測(cè)試性:隨著類版本的不斷更替,必須滿足版本兼容問(wèn)題,所以發(fā)行的版本越多,測(cè)試的難度就越大。
5.降低性能:序列化對(duì)象時(shí),不僅會(huì)序列化當(dāng)前對(duì)象本身,還會(huì)對(duì)該對(duì)象引用的其他對(duì)象也進(jìn)行序列化。如果一個(gè)對(duì)象包含的成員變量是容器類等并深層引用時(shí)(對(duì)象是鏈表形式),此時(shí)序列化開(kāi)銷會(huì)很大,這時(shí)必須要采用其他一些手段處理。
3.序列化的使用場(chǎng)景
1.需要實(shí)現(xiàn)一個(gè)類的對(duì)象傳輸或者持久化。
2.A是B的組件,當(dāng)B需要序列化時(shí),A也實(shí)現(xiàn)序列化會(huì)更容易讓B使用。
4.序列化不適合場(chǎng)景
為了繼承而設(shè)計(jì)的類應(yīng)該盡可能少地去實(shí)現(xiàn)Serializable接口,用戶接口也應(yīng)該盡可能不繼承Serializable接口,原因是子類或?qū)崿F(xiàn)類也要承擔(dān)序列化的風(fēng)險(xiǎn)。
5.序列化需要注意的地方
1)如果父類實(shí)現(xiàn)了Serializable,子類自動(dòng)序列化了,不需要實(shí)現(xiàn)Serializable;
2)若父類未實(shí)現(xiàn)Serializable,而子類序列化了,父類屬性值不會(huì)被保存,反序列化后父類屬性值丟失,需要父類有一個(gè)無(wú)參的構(gòu)造器,子類要負(fù)責(zé)序列化(反序列化)父類的域,子類要先序列化自身,再序列化父類的域。
至于為什么需要父類有一個(gè)無(wú)參的構(gòu)造器,是因?yàn)樽宇愊刃蛄谢陨淼臅r(shí)候先調(diào)用父類的無(wú)參的構(gòu)造器。
實(shí)例:
3)序列化時(shí),只對(duì)對(duì)象狀態(tài)進(jìn)行了保存,對(duì)象方法和類變量等并沒(méi)有保存,因此序列化并不保存靜態(tài)變量值。
4)當(dāng)一個(gè)對(duì)象的實(shí)例變量引用其他對(duì)象,序列化該對(duì)象時(shí)也把引用對(duì)象序列化了。所以組件也應(yīng)該序列化。
5)不是所有對(duì)象都可以序列化,基于安全和資源方面考慮,如Socket/thread若可序列化,進(jìn)行傳輸或保存,無(wú)法對(duì)他們重新分配資源。
總結(jié)
以上是生活随笔為你收集整理的Effective Java之谨慎地实现Serializable(七十四)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Effective Java之不要忽略异
- 下一篇: Effective Java之考虑自定义