Java序列化和反序列化,serialVersionUID詳解

1 什麼是序列化和反序列化

1、定義:
  把對象轉換爲字節序列的過程稱爲對象的序列化。
  把字節序列恢復爲對象的過程稱爲對象的反序列化。
2、用途:
  (1)需要把一些對象持久保存起來,通過序列化將內存種的這些對象轉換爲一系列的字節,就是變成文件。
  (2)需要在網絡上傳送字節序列。

2 如何使用

1、先看一下接口Serializable的源代碼。

package java.io;
// 一大堆註釋
public interface Serializable {
}

空的?一個空的方法怎麼實現對象的序列化和反序列化的?其實註釋裏已經提到了,它只是一個標誌而已,告訴JVM實現這個接口的類的對象可被序列化。
2、上代碼

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Student implements Serializable{
	private static final long serialVersionUID = 1l;
	public static String school = "Java School";
	public int id;
	public String name;
	transient String address;
	public Student(int id, String name, String address) {
		this.id = id;
		this.name = name;
		this.address = address;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "Student{id = "+id+", name = "+name+", address = "+address+"}";
	}
}
public class MySeriaalizable{
	public static void main(String[] args) {
		File file = new File("D:/test.txt");
		
		Student s1 = new Student(1001, "Student1", "幸福路1號");
		// 序列化
		try {
			ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
			out.writeObject(s1);
			out.close();
		}catch (Exception e) {
			e.printStackTrace();
		}
		
		// 反序列化
		try {
			ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
			Student s2 = (Student) in.readObject();
			System.out.println(s2.toString());
			System.out.println(s1.equals(s2));
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
// 代碼輸出
Student{id = 1001, name = Student1, address = null}
false

使用起來非常方便,只需要ObjectOutputStream的 writeObject(Object object) 方法實現序列化,ObjectInputStream的readObject() 方法實現反序列化。
代碼輸出address=null?看一下序列化的結果是什麼?
在這裏插入圖片描述
可以看到test.txt文件中還有一些亂碼,這不重要。重要的是可以很清楚的看到裏面有id, name, 但是沒有school, address, 這是因爲被transient修飾的字段不會被序列化;另外static修飾的屬性屬於類,不僅僅屬於某個對象,序列化操作的是對象,所以靜態變量也不會被序列化。

3 爲什麼使用serialVersionUID

serialVersionUID非必需但很有必要,如果自己不聲明,JVM會動態的生成。原則上,序列化後的數據中的serialVersionUID與當前類當中的serialVersionUID一致時,對象才能夠反序列化成功。在序列化過程種,系統將serialVersionUID寫入到序列化的文件中,反序列化時,首先檢測文件中的serialVersionUID和當前類的serialVersionUID是否一致,如果一致則反序列化成功,否則報錯:java.io.InvalidClassException
靠JVM動態聲明serialVersionUID,類發生改變serialVersionUID會發生變化,且不同的編譯器生成的serialVersionUID也會不同。看一下示例,在部分2中代碼基礎上,去掉serialVersionUID進行序列化後,對Student類增加一個屬性(修改或者刪除也一樣),然後對序列化結果直接進行反序列化。

class Student implements Serializable{
	//private static final long serialVersionUID = 1l;
	public static String school = "Java School";
	public int id;
	public String name;
	transient String address;
	public String newStr;
	......  // 和部分2代碼相同
}
public class MySeriaalizable{
	public static void main(String[] args) {
		File file = new File("D:/test.txt");  // 讀取動態生成serialVersionUID序列化的結果
		Student s1 = new Student(1001, "Student1", "幸福路1號");
		
		// 反序列化
		try {
			ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
			Student s2 = (Student) in.readObject();
			System.out.println(s2.toString());
			System.out.println(s1.equals(s2));
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
java.io.InvalidClassException: mytest.Student; local class incompatible: stream classdesc serialVersionUID = -5603698407479578026, local class serialVersionUID = 970959418018661672
	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:621)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
	at mytest.MySeriaalizable.main(MySeriaalizable.java:61)

錯誤提示:stream classdesc serialVersionUID=-5603698407479578026, local class serialVersionUID=970959418018661672,兩次動態生成的serialVersionUID不同。
如果自己聲明serialVersionUID,則不會出現這個錯誤,在反序列化生成的對象只有未發生改變的屬性的賦值,比如將“name”改名爲“name1”後的反序列化結果爲:

Student{id = 1001, name = null, address = null}
false
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章