通過反序列化生成對象的過程主要由以下幾個步驟:
1、創建一個對象輸入流,它可以包裝一個其他類型的源輸入流,如文件輸入流;
2、 通過對象輸入流的readObject()方法讀取對象。
其中正是readObject方法返回了一個對象,這個對象就是根據序列化生成的文件而創建的對象,所以反序列化如何創建對象關鍵就在於readObject方法的實現,那就來探析一下它的實現,它的源碼如下:
public final Object readObject() throws IOException, ClassNotFoundException { if (enableOverride) { return readObjectOverride(); } // if nested read, passHandle contains handle of enclosing object int outerHandle = passHandle; try { Object obj = readObject0(false); handles.markDependency(outerHandle, passHandle); ClassNotFoundException ex = handles.lookupException(passHandle); if (ex != null) { throw ex; } if (depth == 0) { vlist.doCallbacks(); } return obj; } finally { passHandle = outerHandle; if (closed && depth == 0) { clear(); } } }
由於該方法返回值就是一個Object類型,所以我們重點看實際返回的obj這個對象是怎么創建,可以看出它是通過另一個方法創建,繼續查看readObject0方法的源碼:
private Object readObject0(boolean unshared) throws IOException { boolean oldMode = bin.getBlockDataMode(); if (oldMode) { int remain = bin.currentBlockRemaining(); if (remain > 0) { throw new OptionalDataException(remain); } else if (defaultDataEnd) { /* * Fix for 4360508: stream is currently at the end of a field * value block written via default serialization; since there * is no terminating TC_ENDBLOCKDATA tag, simulate * end-of-custom-data behavior explicitly. */ throw new OptionalDataException(true); } bin.setBlockDataMode(false); } byte tc; while ((tc = bin.peekByte()) == TC_RESET) { bin.readByte(); handleReset(); } depth++; totalObjectRefs++; try { switch (tc) { case TC_NULL: return readNull(); case TC_REFERENCE: return readHandle(unshared); case TC_CLASS: return readClass(unshared); case TC_CLASSDESC: case TC_PROXYCLASSDESC: return readClassDesc(unshared); case TC_STRING: case TC_LONGSTRING: return checkResolve(readString(unshared)); case TC_ARRAY: return checkResolve(readArray(unshared)); case TC_ENUM: return checkResolve(readEnum(unshared)); case TC_OBJECT: return checkResolve(readOrdinaryObject(unshared)); case TC_EXCEPTION: IOException ex = readFatalException(); throw new WriteAbortedException("writing aborted", ex); case TC_BLOCKDATA: case TC_BLOCKDATALONG: if (oldMode) { bin.setBlockDataMode(true); bin.peek(); // force header read throw new OptionalDataException( bin.currentBlockRemaining()); } else { throw new StreamCorruptedException( "unexpected block data"); } case TC_ENDBLOCKDATA: if (oldMode) { throw new OptionalDataException(true); } else { throw new StreamCorruptedException( "unexpected end of block data"); } default: throw new StreamCorruptedException( String.format("invalid type code: %02X", tc)); } } finally { depth--; bin.setBlockDataMode(oldMode); } }
這個方法是readObject方法的底層實現,由於它的返回值類型也是對象類型,所以我們重點看返回的實際對象是哪個,通過觀察和debug發現,開關語句執行時下面這行代碼,checkResolve方法接收的參數類型是對象類型,返回值類型也是對象類型。
case TC_OBJECT: return checkResolve(readOrdinaryObject(unshared));
那我們來查看readOrdinaryObject對象:
private Object readOrdinaryObject(boolean unshared) throws IOException { if (bin.readByte() != TC_OBJECT) { throw new InternalError(); } ObjectStreamClass desc = readClassDesc(false); desc.checkDeserialize(); Class<?> cl = desc.forClass(); if (cl == String.class || cl == Class.class || cl == ObjectStreamClass.class) { throw new InvalidClassException("invalid class descriptor"); } Object obj; try { obj = desc.isInstantiable() ? desc.newInstance() : null; } catch (Exception ex) { throw (IOException) new InvalidClassException( desc.forClass().getName(), "unable to create instance").initCause(ex); } passHandle = handles.assign(unshared ? unsharedMarker : obj); ClassNotFoundException resolveEx = desc.getResolveException(); if (resolveEx != null) { handles.markException(passHandle, resolveEx); } if (desc.isExternalizable()) { readExternalData((Externalizable) obj, desc); } else { readSerialData(obj, desc); } handles.finish(passHandle); if (obj != null && handles.lookupException(passHandle) == null && desc.hasReadResolveMethod()) { Object rep = desc.invokeReadResolve(obj); if (unshared && rep.getClass().isArray()) { rep = cloneArray(rep); } if (rep != obj) { // Filter the replacement object if (rep != null) { if (rep.getClass().isArray()) { filterCheck(rep.getClass(), Array.getLength(rep)); } else { filterCheck(rep.getClass(), -1); } } handles.setObject(passHandle, obj = rep); } } return obj; }
此處我們重點看的還應該是產生實際返回值的地方,也就是這塊:
obj = desc.isInstantiable() ? desc.newInstance() : null;
所以這就是為什么通過反序列化創建對象的時候,並不會執行被序列化對象的構造方法。
對於實現Serializable接口的類,並不要求該類具有一個無參的構造方法, 因為在反序列化的過程中實際上是去其繼承樹上找到一個沒有實現Serializable接口的父類(最終會找到Object),然后構造該類的對象,再逐層往下的去設置各個可以反序列化的屬性(也就是沒有被transient修飾的非靜態屬性)。
我們通過一個具體的案例就可以看出來:
import java.io.Serializable; public class Users implements Serializable { private String username; private int age; private String sex; public Users() { System.out.println("調用了構造方法"); } /*
get和set方法
*/
…………
}
創建一個測試類:
import java.io.*; public class TestUsers { public static void main(String[] args) { try { System.out.println("開始序列化。。。。。"); Users users = new Users(); users.setUsername("fym"); users.setAge(23); users.setSex("nan"); FileOutputStream fs = new FileOutputStream("users.ser"); ObjectOutputStream os = new ObjectOutputStream(fs); os.writeObject(users); os.close(); fs.close(); System.out.println("開始反序列化。。。。。"); FileInputStream fileInputStream = new FileInputStream("users.ser"); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); Users o = (Users)objectInputStream.readObject(); System.out.println(o); fileInputStream.close(); objectInputStream.close(); } catch (Exception e) { e.printStackTrace(); } } }
輸出結果:
開始序列化。。。。。
調用了構造方法
開始反序列化。。。。。
Users{username='fym', age=23, sex='nan'}
我們將其改造一下,讓User類繼承一個沒有序列化的父類:
class ParentsUser{ public ParentsUser(){ System.out.println("調用了父類構造方法"); } } public class Users extends ParentsUser implements Serializable { …… }
再一次執行上面的測試類,輸出結果如下:
開始序列化。。。。。
調用了父類構造方法
調用了構造方法
開始反序列化。。。。。
調用了父類構造方法
Users{username='fym', age=23, sex='nan'}
發現,反序列化創建對象的時候,果然調用了離User類最近的沒有序列化的超類的無參構造函數。