天天看點

Java序列化中的Serializable也有你不知道的内幕!

作者:SnowTiger
Java序列化中的Serializable也有你不知道的内幕!

JDK中對Serializable接口的定義下:

Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized. All subtypes of a serializable class are themselves serializable. The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.

白話文表述就是: 類的可序列化性早實作Serializable接口來啟用,未實作此接口的類不能進行序列化和反序列化。同時呢,一個類變成可序列化後,它的所有子類也将可序列化。Serializable接口沒有方法,沒有屬性定義,僅僅是個可序列化辨別接口。

看起來是不是很簡單,但是JAVA本身的這個序列化卻是牽扯很廣大呀,裡面門道不見得比那些高大上的序列化家族少哇。

一. 一個類能不能被序列化,到底有哪些要求?先從最基礎的來說,

1)首先,上面已經說了,必須得實作 Serializable 接口,這是第一步,可以了解為這是一個開關。接下來就到這個類自身的定義了,我們平常呢,定義一個類,裡面肯定有一些屬性,這些屬性呢有各自的類型。那如果我們需要這個類能正常被序列化的話呢,這個時候類裡面的屬性就不能随意定義了,比如:下面這個示例中

static class Vo1 implements Serializable { private int num; private String name; private Integer use; private FieldX fieldX; public Vo1(int num, String name, Integer use, FieldX fieldX) { this.num = num; this.name = name; this.use = use; this.fieldX = fieldX; } public Vo1(int num, String name, Integer use) { this.num = num; this.name = name; this.use = use; } @Override public String toString() { return new StringJoiner(", ", Vo1.class.getSimpleName() + "[", "]").add("num=" + num).add("name='" + name + "'").add("use=" + use).add("fieldX=" + fieldX).toString(); } }static class FieldX{ private String name; private String value; public FieldX(String name, String value) { this.name = name; this.value = value; } @Override public String toString() { return new StringJoiner(", ", FieldX.class.getSimpleName() + "[", "]").add("name='" + name + "'").add("value='" + value + "'").toString(); } } @Test void testSer() throws Exception{ Vo1 vo1 = new Vo1(123,"Test",100); Vo1 vo2 = new Vo1(123,"Test",100,new FieldX("F1","V1")); System.out.println("vo1"); try(ObjectOutputStream serializable=new ObjectOutputStream(new FileOutputStream("G://vo1.txt"))) { serializable.writeObject(vo1); } System.out.println("vo2"); try(ObjectOutputStream serializable=new ObjectOutputStream(new FileOutputStream("G://vo2.txt"))) { serializable.writeObject(vo2); } }           

,vo1執行個體可以正常序列化,而vo2執行個體無法正常序列化,提示的是FieldX類型不可序列化。

2)是以要保證一個類可以被正常序列化,在實作Serializable接口的基礎上,還得保證此類中所有需要被序列化的屬性都滿足可序列化條件,FieldX類也同樣需要去實作接口Serializable,以此類推。那如果存在不需要被序列化的屬性怎麼辦呢?我們後面再補充此内容。

3) 類中所有屬性不包含類屬性哦,就是類裡面的靜态變量等是不在上述範圍内的,因為序列化本質。二. 類序列化目的是什麼?簡單來說就是:我們的程式在運作過程中本身産生的對象執行個體,本身是在JVM中存儲的,說直白點就是隻存在于記憶體中,這也就意味着在程式終止時這些記憶體中的對象執行個體理論上都會被釋放回收。那麼,如果說我們有一些場景需要在程式運作後産生的對象執行個體在下次程式運作時仍然可以通路和使用,甚至于一個程式中産生的對象執行個體要在另外的程式中可以通路并使用,要怎麼滿足這些應用場景呢?答案是序列化。

序列化有兩個主要目的:

1 是對象執行個體狀态的持久化,存儲到硬碟或其它可以持久存儲的媒體,以保證在程式終止時不會随記憶體釋放而消失的,可以持久儲存。

2 是對象執行個體的共享,序列化後的對象執行個體可以通過網絡等媒體發送和傳播,可以在其它程式中通路和使用。

三. JDK序列化的優劣.

目前來說,在JAVA領域有很多優秀的序列化支援,JDK本身的序列化也被諸多诟病,其性能并不具備優勢。其主要的優勢在本人看來可能就是通用性和簡單化了,是以在一些性能不敏感的節點(要求不高),JDK序列化仍然保持活躍。如果在一些性能敏感的節點,可能大家需要去參考一些更具優勢的協定,如:protobuf,json等序列化方式。

本期旨在簡單介紹JDK序列化的基本内容,下期繼續來講"JDK序列化中的坑!"。

Java序列化中的Serializable也有你不知道的内幕!