Serializable
是一種用來處理對象流的機制。對象流就是將運行時對象的狀態進行流化,即轉換成二進制。說白了,就是將正在運行中程序的對象的狀態/內容轉換成二進制進行傳輸,持久化的操做。java
在 Java 中,序列化是在 jdk 1.1 時引入的特性。Serializable 的定義安全
public interface Serializable {
}
複製代碼
只有這麼個接口,一旦某類實現了該接口,那麼該類就有了序列化的能力,但嚴格來講,不必定能序列化/反序列化成功,爲撒吶?先來看個 demo數據結構
舉個栗子🌰,有一 Women
類,該類有三個屬性,分別是age
,weight
和name
,咱們來試試怎麼序列/反序列化。ide
先來個 Women classui
//Women.class
public class Women implements Serializable {
private static final long serialVersionUID = 1L;
private Integer age;
private String name;
private Float weight;
public Women(String name, int age, float weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
'''
setter/getter
'''
}
複製代碼
public static void main(String[] args) throws IOException {
Women women = new Women("xiao ju",18, 45.1f);
File file = new File("xiaoju.txt");
FileOutputStream output = new FileOutputStream(file);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(output);
objectOutputStream.writeObject(women);
output.close();
objectOutputStream.close();
}
複製代碼
public static void main(String[] args) throws IOException, ClassNotFoundException {
File file = new File("xiaoju.txt");
FileInputStream input= new FileInputStream(file);
ObjectInputStream objectInputStream = new ObjectInputStream(input);
Women women = (Women) objectInputStream.readObject();
input.close();
objectInputStream.close();
}
複製代碼
這就是序列化/反序列化的過程。能夠看到咱們在Woemen
類中,不只實現了Serializable
接口外,還加了一個serialVersionUID
,固然了,若是咱們不手動加,那麼系統也會根據當前類的結構會初始化一個UID
,它的做用是什麼呢?this
當進行序列化的時候,UID
會和當前對象的狀態一同持續久化,在反序列化的時候,會檢測當前類的UID
是否和持久化的UID
一致,若是一致,那麼反序列化成功,不然失敗。spa
若是咱們沒有指定UID
的化,系統在初始化一個UID
後,隨着對象的持久化,若是咱們這個時候改了該類的數據結構,那麼這個類的UID
就會發生改變(系統初始化的UID
是根據類的數據結構算出來的),因此在反序列化的時候,就會檢測到UID
不一致,那麼就會失敗。因此,通常咱們都會加上一個UID
。code
確實很差,不要你以爲,要我以爲,不是全部的類都想要序列化的,有些類是比較敏感的,好比用戶類,卡號類... 對於序列化的對象的信息是很容易被破解的,不能保證其安全性。cdn
兩種方式:對象
static
修飾符。前面咱們說到,序列化/反序列化的都是程序正在運行中的對象的狀態,而被static
修飾的屬性/方法實際上是屬於類的狀態,不屬於處於內存中的對象。transient
修飾,transient
不能修飾方法/類。一旦屬性被transient
修飾,那麼該屬性就不會被序列/反序列化。類成員
爲了減小存儲,傳輸空間,從提升效率,那麼在進行序列化的時候,能夠將不須要序列化的屬性經過 static
和transient
關鍵字修飾排除掉。
繼承關係
Serializable
接口,子類序列化後,那麼父類也會實現系列化Serializable
接口,子類被序列化後,父類將不會被序列化引用關係
若是一個類實現了序列化,而且引用了一個對象。該對象所屬類實現了Serializable
接口,那麼會改對象也會被序列化,不然會拋出java.io.NotSerializableExeception
。
前面咱們說到,實現了Serializable
接口的類,能夠將整個或部分對象的狀態進行序列化/反序列化。那麼若是咱們想要更加定製化的序列化/反序列化一些東西的話,那麼咱們就須要用到Externalizable
,好比:在序列化的時候我想保存一個時間,反序列化的時候我但願獲取到這個時間,可是這個時間我不想放到類中。
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
複製代碼
能夠看到Externalizable
除了實現了Serializable
接口外,還新增了兩個方法,這兩個方法就是能夠在序列化和反序列化的時候作一些定製的東西。仍是拿Women
來看。
//Women.class
public class Women implements Externalizable {
private static final long serialVersionUID = 1L;
private Integer age;
private String name;
private Float weight;
public Women(String name, int age, float weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(new Date());
out.writeObject(this.name);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println(in.readObject());
this.name = (String) in.readObject();
}
'''
setter/getter
'''
}
複製代碼