一、寫在開頭 在上一篇學(xué)習(xí)序列化的文章中我們提出了這樣的一個(gè)問題: “如果在我的對象中,有些變量并不想被序列化應(yīng)該怎么辦呢?” 當(dāng)時(shí)給的回答是:不想被序列化的變量我們可以使用transient或static關(guān)鍵字修飾;transient 關(guān)鍵字的作用是阻止實(shí)例中那些用此關(guān)鍵字修飾的的變量序列化;當(dāng)對
在上一篇學(xué)習(xí)序列化的文章中我們提出了這樣的一個(gè)問題:
“如果在我的對象中,有些變量并不想被序列化應(yīng)該怎么辦呢?”
當(dāng)時(shí)給的回答是:不想被序列化的變量我們可以使用
transient
或
static
關(guān)鍵字修飾;transient 關(guān)鍵字的作用是阻止實(shí)例中那些用此關(guān)鍵字修飾的的變量序列化;當(dāng)對象被反序列化時(shí),被 transient 修飾的變量值不會被持久化和恢復(fù);而static關(guān)鍵字修飾的變量并不屬于對象本身,所以也同樣不會被序列化!
當(dāng)時(shí)沒有解釋具體為什么static和transient 關(guān)鍵字修飾的變量就不能被序列化了,這個(gè)問題實(shí)際上在很多大廠的面試中都可能會被問及。我們今天在這篇中進(jìn)行解釋吧。
我們先通過一個(gè)實(shí)戰(zhàn)案例,去看一看用static和transient 關(guān)鍵字修飾后的變量,序列化與反序列化后的現(xiàn)象。
public class TestService {
public static void main(String[] args) throws IOException {
//初始化對象信息
Person person = new Person();
person.setName("JavaBuild");
person.setAge(30);
System.out.println(person.getName()+" "+person.getAge());
//序列化過程
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("E:\\person.txt"));) {
objectOutputStream.writeObject(person);
} catch (IOException e) {
e.printStackTrace();
}
person.par1 = "序列化后靜態(tài)字段";
//反序列化過程
try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("E:\\person.txt"));) {
Person p = (Person) objectInputStream.readObject();
System.out.println(p);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Person implements Serializable{
private static final long serialVersionUID = 8711922740433840551L;
private String name;
private int age;
public static String par1 = "靜態(tài)字段";
transient String par2 = "臨時(shí)字段";
transient int high = 175;
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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
", par1=" + par1 +
", high=" + high +
", par2='" + par2 + '\'' +
'}';
}
}
在Person類中,我們定義了兩個(gè)正常的屬性,姓名與年齡,同時(shí)呢,我們也分別定義了一個(gè)靜態(tài)字段和兩個(gè)臨時(shí)字段,輸出結(jié)果為:
JavaBuild 30
Person{name='JavaBuild', age=30, par1=序列化后靜態(tài)字段, high=0, par2='null'}
對于使用static關(guān)鍵字修飾的par1來說,在整個(gè)序列化過程中,它并未參與,原因是:我們在序列化與反序列化之間插入了屬性的重新賦值操作,最后輸出中打印出的是最新賦值,說明僅是調(diào)用了實(shí)例對象的屬性值,而不是反序列化的結(jié)果。
而對于transient 關(guān)鍵字修飾high和par2,在序列化時(shí)直接被忽略了。從輸出結(jié)果看就更加的明了了,int類型直接還原為默認(rèn)值0,而String類型直接為null。
什么原因呢?咱們繼續(xù)往下看。
在之前的文章中,我們已經(jīng)解釋過了,在序列化時(shí)Serializable只是作為一種標(biāo)識接口,告訴程序我這個(gè)對象需要序列化,那么真正的實(shí)現(xiàn)還要以來序列化流,比如寫出到文件時(shí),我們需要用到的ObjectOutputStream,它在序列化的時(shí)候會依次調(diào)用 writeObject()→writeObject0()→writeOrdinaryObject()→writeSerialData()→invokeWriteObject()→defaultWriteFields()。
然后最后一步的defaultWriteFields()方法中,會去調(diào)用ObjectStreamClass對象,里面有個(gè)方法為getDefaultSerialFields(),提供了可以被序列化的屬性值。
private static ObjectStreamField[] getDefaultSerialFields(Class> cl) {
// 獲取該類中聲明的所有字段
Field[] clFields = cl.getDeclaredFields();
ArrayList list = new ArrayList<>();
int mask = Modifier.STATIC | Modifier.TRANSIENT;
// 遍歷所有字段,將非 static 和 transient 的字段添加到 list 中
for (int i = 0; i < clFields.length; i++) {
Field field = clFields[i];
int mods = field.getModifiers();
if ((mods & mask) == 0) {
// 根據(jù)字段名、字段類型和字段是否可序列化創(chuàng)建一個(gè) ObjectStreamField 對象
ObjectStreamField osf = new ObjectStreamField(field.getName(), field.getType(), !Serializable.class.isAssignableFrom(cl));
list.add(osf);
}
}
int size = list.size();
// 如果 list 為空,則返回一個(gè)空的 ObjectStreamField 數(shù)組,否則將 list 轉(zhuǎn)換為 ObjectStreamField 數(shù)組并返回
return (size == 0) ? NO_FIELDS :
list.toArray(new ObjectStreamField[size]);
}
這段源碼中,定義一個(gè)mask標(biāo)記變量,用于接收訪問修飾符中包含STATIC與TRANSIENT的屬性,并在后面的if判斷中,將這種mask的過濾掉,從而實(shí)現(xiàn)遍歷所有字段,將非 static 和 transient 的字段添加到 list 中。
而這段源碼就證明了,為什么在對象序列化過程中,static和transient不會被序列化!
好啦,今天針對為什么static和transient關(guān)鍵字修飾的變量不能被序列化進(jìn)行了一個(gè)解釋,下次大家在面試的時(shí)候再被問道就可以這樣回答啦,不過,還有的BT面試官會問transient關(guān)鍵字修飾的變量真的不能被序列化嗎?這個(gè)問題咱們后面繼續(xù)討論哈。
小編推薦閱讀機(jī)器學(xué)習(xí):神經(jīng)網(wǎng)絡(luò)構(gòu)建(下)
閱讀華為Mate品牌盛典:HarmonyOS NEXT加持下游戲性能得到充分釋放
閱讀實(shí)現(xiàn)對象集合與DataTable的相互轉(zhuǎn)換
閱讀鴻蒙NEXT元服務(wù):論如何免費(fèi)快速上架作品
閱讀算法與數(shù)據(jù)結(jié)構(gòu) 1 - 模擬
閱讀5. Spring Cloud OpenFeign 聲明式 WebService 客戶端的超詳細(xì)使用
閱讀Java代理模式:靜態(tài)代理和動態(tài)代理的對比分析
閱讀Win11筆記本“自動管理應(yīng)用的顏色”顯示規(guī)則
閱讀本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請發(fā)郵件[email protected]
湘ICP備2022002427號-10 湘公網(wǎng)安備:43070202000427號© 2013~2025 haote.com 好特網(wǎng)