序列化就是Java對象轉化爲字節序列的過程,反序列化則是把字節序列恢復爲Java對象的過程。
網絡中的各種通信傳輸可以傳送文字、圖片、文件都是以二進制字節的序列進行傳輸的,因此
如果兩個Java進程之間傳輸對象也需要將對象進行序列化傳輸和反序列化進行接收。Java的JDK
開發包中提供了將Java對象序列化和反序列化的方法:ObjectOutputStream和ObjectInputStram
ObjectOutputStream中的writeObject(Objec obj)將Java對象進行序列化,把得到的字節序列輸出
到一個目標流中;ObjectInputStream的readObject()方法則是將目標流中的字節序列回覆爲Java
對象。
序列化和反序列化的作用:
1.實現Java對象持久化,將序列化數據保存到本地(硬盤)
2.實現Java對象在網絡之間的通訊,將序列化的字節序列通過網絡進行傳輸
在Java中想實現對象的序列化和反序列化很簡單,只需要實現Serializable或者Externalizable接口
Serializable就是一個接口沒有可實現的方法,默認就會將實現該接口的所有聲明的非transient屬性
進行序列化;Externalizable接口需要實現writeExternal和readExternal方法,也就是說該接口是一個
需要手動指定哪些屬性需要進行序列化。
代碼演示
package core.java.serializable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializableDemo {
public static void main(String[] args) {
SerializableDemo demo = new SerializableDemo();
User user = new User(1, "zhangsan", "男");
System.out.println("開始序列化--------------");
demo.writeObject(user);
System.out.println("開始反序列化-------------");
User u = (User)demo.readObject();
System.err.println(u.getId() + "," + u.getName() + "," + u.getSex());
}
/**
* 序列化對象
* @param obj
*/
private void writeObject(Object obj){
try {
ObjectOutputStream ots = new ObjectOutputStream(new FileOutputStream(new File("D:/object.txt")));
ots.writeObject(obj);
ots.flush();
ots.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 反序列化對象
* @return
*/
private Object readObject(){
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:/object.txt")));
Object object = ois.readObject();
ois.close();
return object;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
package core.java.serializable;
import java.io.Serializable;
/**
* 序列化實體
* @author author
*
*/
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 8511909251520938165L;
private int id;
private String name;
private String sex;
public User(int id, String name, String sex){
super();
this.id = id;
this.name = name;
this.sex = sex;
}
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 getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
控制檯輸出結果:開始序列化--------------
開始反序列化-------------
1,zhangsan,男
如果實體類沒有實現序列化接口程序將拋java.io.NotSerializableException異常
另外在將某個對象序列化的時候實現Serializable接口的時候通常都會添加一個靜態
不可改變值的序列化版本號編號,這將是這個序列化對象的唯一標識,如果我們沒有
添加,該類會出現警告的信息提示我們添加,但是如果我們不添加系統會默認給該類
指定一個編號,只是我們沒看到。但是這樣會有一些安全隱患,比如我們將一個對象
持久化到本地,這個時候我們在類中添加一個額外的屬性,再進行反序列化的時候將
本地字節序列恢復到對象的時候就會拋java.io.InvalidClassException異常,、
異常信息:core.java.serializable.User; local class incompatible:
stream classdesc serialVersionUID = -9060100527542415407,
local class serialVersionUID = 8511909251520938165
意思就是本地的類和字節序列中的類不是同一個類,因爲他們兩個類的版本號不一樣。
在進行反序列化的時候本地的類是無效的。所以當我們在進行對象序列化的時候一定
要添加上序列化版本號,以防程序拋異常。