發(fā)現(xiàn)網(wǎng)絡(luò)上對(duì)于反序列化時(shí),什么時(shí)候需要空參構(gòu)造器都模糊不清噪叙,也沒(méi)有一個(gè)準(zhǔn)確的一個(gè)概念矮锈,因此我們由現(xiàn)象到源碼一探究竟
- 先上一個(gè)父類(lèi)和子類(lèi)都沒(méi)有空參構(gòu)造器,父類(lèi)實(shí)現(xiàn)Serializable接口睁蕾,子類(lèi)間接實(shí)現(xiàn)Serializable接口,序列化子類(lèi)對(duì)象sub
class Data implements Serializable{
private int n;
public Data(int n){
this.n = n;
}
public String toString(){
return Integer.toString(n);
}
}
class sub extends Data{
private static int m = 6;
private int k;
public sub(int n) {
super(n);
}
}
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out"));
sub d = new sub(10);
out.writeObject(d);
ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out"));
sub f = (sub) in.readObject();
序列化成功了苞笨,說(shuō)明這種情況父類(lèi)子類(lèi)不需要空參構(gòu)造器,序列化出來(lái)的文件是這樣的
?í ?sr main.subbê??uéaP? ?I ?kxr main.Data?????t÷?? ?I ?nxp
- 接下來(lái)嘗試父類(lèi)和子類(lèi)都沒(méi)有空參構(gòu)造器子眶,父類(lèi)不實(shí)現(xiàn)Serializable接口瀑凝,子類(lèi)實(shí)現(xiàn)Serializable接口,序列化子類(lèi)對(duì)象sub
class Data{
private int n;
public Data(int n){
this.n = n;
}
public String toString(){
return Integer.toString(n);
}
}
class sub extends Data implements Serializable{
private static int m = 6;
private int k;
public sub(int n) {
super(n);
}
}
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out"));
sub d = new sub(10);
out.writeObject(d);
ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out"));
sub f = (sub) in.readObject();
結(jié)果會(huì)發(fā)現(xiàn)提示找不到可用的構(gòu)造器
Exception in thread "main" java.io.InvalidClassException: main.sub; no valid constructor
at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:150)
at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:790)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1782)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
at main.Worm.main(Worm.java:81)
序列化出的文件是這樣的
?í ?sr main.subμ|?)CO?I? ?I ?kxp
會(huì)什么會(huì)出現(xiàn)這種情況呢,最后我們追蹤到ObjectStreamClass類(lèi)的一個(gè)方法,是引起異常的主要原因
//ObjectStreamClass.java
/**
* Returns subclass-accessible no-arg constructor of first non-serializable
* superclass, or null if none found. Access checks are disabled on the
* returned constructor (if any).
*/
private static Constructor<?> getSerializableConstructor(Class<?> cl) {
Class<?> initCl = cl;
while (Serializable.class.isAssignableFrom(initCl)) {
if ((initCl = initCl.getSuperclass()) == null) {
return null;
}
}
try {
Constructor<?> cons = initCl.getDeclaredConstructor((Class<?>[]) null);
int mods = cons.getModifiers();
if ((mods & Modifier.PRIVATE) != 0 ||
((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
!packageEquals(cl, initCl)))
{
return null;
}
cons = reflFactory.newConstructorForSerialization(cl, cons);
cons.setAccessible(true);
return cons;
} catch (NoSuchMethodException ex) {
return null;
}
}
方法的注釋是
Returns subclass-accessible no-arg constructor of first non-serializable superclass, or null if none found. Access checks are disabled on the returned constructor (if any)臭杰。
翻譯過(guò)來(lái)的意思就是粤咪,返回第一個(gè)非可序列化超類(lèi)的子類(lèi)可訪問(wèn)的no-arg構(gòu)造函數(shù),如果沒(méi)有找到則返回null渴杆。在返回的構(gòu)造函數(shù)上禁用訪問(wèn)檢查(如果有的話)寥枝。
因此我們就明白了
為什么在第一個(gè)例子中沒(méi)有丟出InvalidClassException異常,因?yàn)榈谝粋€(gè)例子的第一個(gè)非可序列化超類(lèi)是Object磁奖,Object沒(méi)有顯式的構(gòu)造方法囊拜,因此就是默認(rèn)有默認(rèn)的空參構(gòu)造方法,符合條件
第二個(gè)例子中丟出InvalidClassException異常是因?yàn)榈诙€(gè)例子的第一個(gè)非可序列化超類(lèi)是Date,因?yàn)镈ate沒(méi)有顯示的構(gòu)造方法比搭,因此丟出異常
最后我們驗(yàn)證一下冠跷,如果給Date類(lèi)加上默認(rèn)空參構(gòu)造方法,是否還能編譯通過(guò)
class Data{
private int n;
public Data(int n){
this.n = n;
}
public Data(){
this.n = 10;
}
public String toString(){
return Integer.toString(n);
}
}
最后返回成功了,這也驗(yàn)證了我們的想法蜜托。
最后我們得到的結(jié)論是抄囚,序列化時(shí),如果第一個(gè)非可序列化超類(lèi)非Object類(lèi)橄务,那么一定要預(yù)留一個(gè)空參構(gòu)造方法幔托,否則就會(huì)序列化失敗
關(guān)于其他JAVA序列化的結(jié)論驗(yàn)證可以查看我的另一篇文章
http://www.reibang.com/p/7340dcb80a54