Java——transient and 序列化
序列化
序列化 (Serialization)是將物件的狀態資訊轉換為可以儲存或傳輸的形式的過程。
在網路傳輸過程中,可以是位元組或是XML,json等格式。而位元組的,XML,json編碼格式可以還原完全相等的物件。這個相反的過程又稱為反序列化。
transient
java 的transient關鍵字為我們提供了便利,你只需要實現Serilizable介面,將不需要序列化的屬性前新增關鍵字transient,序列化物件的時候,這個屬性就不會序列化到指定的目的地中。
序列化兩種方式
1.物件實現了序列化介面Serializable
2.第二種方式為實現介面Externalizable
其實這個介面也是繼承了Serializable介面,該介面中有兩個方法 void writeExternal(ObjectOutput out)
和 void readExternal(ObjectInput in)
,所以使用這種方式,要實現這兩個介面。在 writeExternal()
方法裡定義了哪些屬性可以序列化,例如 out.writeObject(userName)
,哪些不可以序列化,物件在經過這裡就把規定能被序列化的序列化儲存檔案,不能序列化的不處理,然後在反序列的時候自動呼叫 readExternal()
方法,如userName=(String) in.readObject()
,根據序列順序挨個讀取進行反序列,並自動封裝成物件返回。
可以看出來Externalizable形式的序列化會更靈活一些,可以自己定義哪些欄位需要序列化,和transient的功能有些類似。
程式碼示例
程式碼中有兩種實現方式,第一種的測試程式碼被註釋了。
public class SerializationPractice {
public void serializableTest() {
// Worker worker = new Worker();
Worker1 worker = new Worker1();
worker.setAge(30);
worker.setName("gary");
worker.setHeight(170);
System.out.println(worker);
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(
new FileOutputStream("/Users/gary/Documents/serializeTest.txt"))) {
objectOutputStream.writeObject(worker);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void deserializeTest() {
try (ObjectInputStream objectInputStream = new ObjectInputStream(
new FileInputStream("/Users/gary/Documents/serializeTest.txt"))) {
// Worker worker = (Worker) objectInputStream.readObject();
Worker1 worker = (Worker1) objectInputStream.readObject();
System.out.println(worker);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SerializationPractice practice = new SerializationPractice();
//序列化
practice.serializableTest();
//反序列化
//practice.deserializeTest();
}
}
class Worker implements Serializable {
private static final long serialVersionUID = 2L;
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "name=" + name + " ,age=" + age;
}
}
class Worker1 implements Externalizable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private int height;
public Worker1() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
return "name=" + name + ",age=" + age + ",height=" + height;
}
@Override
public void writeExternal(ObjectOutput objectOutput) {
try {
objectOutput.writeObject(name);
objectOutput.writeInt(age);
objectOutput.writeInt(height);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void readExternal(ObjectInput objectInput) {
try {
name = (String) objectInput.readObject();
age = objectInput.readInt();
height = objectInput.readInt();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
實現介面Externalizable的序列化時要注意一下情況:
writeExternal方法中沒序列化的屬性,反序列化後得到的是屬性型別的預設值,和 transient 作用類似。
實現介面Externalizable的類要提供無引數的建構函式,否則會報下面的錯誤
java.io.InvalidClassException: javabase.serialization.Worker1; no valid constructor
在使用Externalizable進行序列化的時候,在讀取物件時,會呼叫被序列化類的無參構造器去建立一個新的物件,然後再將被儲存物件的欄位的值分別填充到新物件中。所以,實現Externalizable介面的類必須要提供一個public的無參的構造器。
序列化ID
虛擬機器是否允許反序列化,不僅取決於類路徑和功能程式碼是否一致,一個非常重要的一點是兩個類的序列化 ID 是否一致(就是 private static final long serialVersionUID
)。
序列化時 serialVersionUID=1L
,然後反序列化是修改Worker類的 serialVersionUID=2L
,就會報下面的錯誤。
java.io.InvalidClassException: javabase.serialization.Worker; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
總結
- 如果一個類想被序列化,需要實現Serializable介面或Externalizable介面。否則將丟擲NotSerializableException異常,這是因為,在序列化操作過程中會對型別進行檢查,要求被序列化的類必須屬於Enum、Array和Serializable型別其中的任何一種。
- 在變數宣告前加上該關鍵字,可以阻止該變數被序列化到檔案中。
- 在類中增加writeObject 和 readObject 方法可以實現自定義序列化策略
- 序列化並不儲存靜態變數。
參考資料
相關文章
- Java 中的 transient 關鍵字和物件序列化Java物件
- Java物件表示方式1:序列化、反序列化和transient關鍵字的作用Java物件
- java transient簡介Java
- [java]transient關鍵字Java
- java transient關鍵字Java
- 在 Java 中如何使用 transientJava
- Java transient 的作用及使用方法Java
- Java中transient關鍵字的作用Java
- Java transient關鍵字使用總結Java
- 被遺忘的Java關鍵字:transientJava
- java序列化Java
- Java序列化、反序列化、反序列化漏洞Java
- Java的序列化和反序列化Java
- Java的序列化與反序列化Java
- Java--序列化與反序列化Java
- 什麼是Java序列化,如何實現java序列化Java
- Java安全基礎之Java序列化與反序列化Java
- java物件序列化Java物件
- Serializable java序列化Java
- java的序列化Java
- java反序列化Java
- transient和synchronized的使用synchronized
- java 序列化與反序列化例項Java
- Java中的序列化與反序列化Java
- [Java基礎]序列化和反序列化Java
- Not-null property references a transient value - transient instance must be saved before current opeNull
- 面試官:transient關鍵字修飾的變數當真不可序列化?我:煩請先生教我!面試變數
- Java序列化(Serializable)與反序列化詳解Java
- java 物件序列化要序列化那些內容Java物件
- 淺談Java序列化Java
- java的序列化SerializableJava
- java自定義序列化Java
- Java基礎——序列化Java
- 深度解析JAVA序列化Java
- java中的序列化Java
- 理解Java物件序列化Java物件
- Java物件的序列化和反序列化實踐Java物件
- 從java的序列化和反序列化說起Java