title: Java 序列化
categories: 后臺開發(fā)
tags:
- java
- 基礎(chǔ)知識
- 必備
Java 序列化
什么是序列化?為什么需要序列化
- 序列化:將 Java 對象轉(zhuǎn)換成字節(jié)流的過程陌宿。
- 反序列化:將字節(jié)流轉(zhuǎn)換成 Java 對象的過程。
當(dāng) Java 對象需要在網(wǎng)絡(luò)上傳輸
或者 持久化存儲到文件中
時舶得,就需要對 Java 對象進行序列化處理弥虐。
注意事項:
某個類可以被序列化,則其子類也可以被序列化
聲明為 static 和 transient 的成員變量珠插,不能被序列化颖对。static 成員變量是描述類級別的屬性,transient 表示臨時數(shù)據(jù)
反序列化讀取序列化對象的順序要保持一致
Java 序列化方式有幾種缤底?
答案: 三種
1. 實現(xiàn) Serializable 接口(隱式序列化)
通過實現(xiàn) Serializable 接口,這種是隱式序列化(不需要手動)江解,這種是最簡單的序列化方式徙歼,會自動序列化所有非 static 和 transient 關(guān)鍵字修飾的成員變量。
Java 的序列化機制是通過在運行時判斷類的 serialVersionUID 來驗證版本一致性的魄梯。在進行反序列化時,JVM 會把傳來的字節(jié)流中的 serialVersionUID 與本地相應(yīng)實體(類)的 serialVersionUID 進行比較灭翔,如果相同就認為是一致的辣苏,可以進行反序列化哄褒,否則就會出現(xiàn)序列化版本不一致的異常狭园。
class Student implements Serializable{
private String name;
private int age;
public static int QQ = 1234;
private transient String address = "CHINA";
Student(String name, int age ){
this.name = name;
this.age = age;
}
public String toString() {
return "name: " + name + "\n"
+"age: " + age + "\n"
+"QQ: " + QQ + "\n"
+ "address: " + address;
}
public void SetAge(int age) {
this.age = age;
}
}
public class SerializableDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//創(chuàng)建可序列化對象
System.out.println("原來的對象:");
Student stu = new Student("Ming", 16);
System.out.println(stu);
//創(chuàng)建序列化輸出流
ByteArrayOutputStream buff = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(buff);
//將序列化對象存入緩沖區(qū)
out.writeObject(stu);
//修改相關(guān)值
Student.QQ = 6666; // 發(fā)現(xiàn)打印結(jié)果QQ的值被改變
stu.SetAge(18); //發(fā)現(xiàn)值沒有被改變
//從緩沖區(qū)取回被序列化的對象
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buff.toByteArray()));
Student newStu = (Student) in.readObject();
System.out.println("序列化后取出的對象:");
System.out.println(newStu);
}
}
2.實現(xiàn) Externalizable 接口。(顯式序列化)**
Externalizable 接口繼承自 Serializable, 我們在實現(xiàn)該接口時罚舱,必須實現(xiàn)writeExternal()和readExternal()方法
,而且只能通過手動進行序列化管闷,并且兩個方法是自動調(diào)用的窃肠,因此,這個序列化過程是可控的冤留,可以自己選擇哪些部分序列化。
public class Blip implements Externalizable{
private int i ;
private String s;
public Blip() {}
public Blip(String x, int a) {
System.out.println("Blip (String x, int a)");
s = x;
i = a;
}
public String toString() {
return s+i;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
// TODO Auto-generated method stub
System.out.println("Blip.writeExternal");
out.writeObject(s);
out.writeInt(i);
//
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// TODO Auto-generated method stub
System.out.println("Blip.readExternal");
s = (String)in.readObject();
i = in.readInt();
}
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
System.out.println("Constructing objects");
Blip b = new Blip("A Stirng", 47);
System.out.println(b);
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("F://Demo//file1.txt"));
System.out.println("保存對象");
o.writeObject(b);
o.close();
//獲得對象
System.out.println("獲取對象");
ObjectInputStream in = new ObjectInputStream(new FileInputStream("F://Demo//file1.txt"));
System.out.println("Recovering b");
b = (Blip)in.readObject();
System.out.println(b);
}
}
3.實現(xiàn) Serializable 接口+添加 writeObject() 和 readObject() 方法。(顯+隱序列化)
如果想將方式一和方式二的優(yōu)點都用到的話泊窘,可以采用方式三, 先實現(xiàn) Serializable 接口瓜贾,并且添加writeObject()和readObject()方法携悯。注意這里是添加,不是重寫或者覆蓋憔鬼。
但是添加的這兩個方法必須有相應(yīng)的格式。
- 方法必須要被 private 修飾 ----->才能被調(diào)用
- 第一行調(diào)用默認的 defaultRead/WriteObject(); ----->隱式序列化非static和transient
- 調(diào)用 read/writeObject() 將獲得的值賦給相應(yīng)的值 --->顯式序列化
public class SerDemo implements Serializable{
public transient int age = 23;
public String name ;
public SerDemo(){
System.out.println("默認構(gòu)造器咸灿。侮叮。悼瘾。");
}
public SerDemo(String name) {
this.name = name;
}
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
stream.writeInt(age);
}
private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException {
stream.defaultReadObject();
age = stream.readInt();
}
public String toString() {
return "年齡" + age + " " + name;
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
SerDemo stu = new SerDemo("Ming");
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject(stu);
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
SerDemo stu1 = (SerDemo) in.readObject();
System.out.println(stu1);
}
}