《Effective Java》已经汇报我们,在单例类中提供一个readResolve要领就可以完成单例特性。这里各人可以本身去测试。
接下来,我们去看看Java提供的反序列化是如何建设工具的!
工具的序列化进程通过ObjectOutputStream和ObjectInputputStream来实现的,那么带着方才的问题,阐明一下ObjectInputputStream的readObject 要领执行环境到底是奈何的。
为了节减篇幅,这里给出ObjectInputStream的readObject的挪用栈:
苏州软件公司 ic T extends EnumT T valueOf(ClassT enumType" class="aligncenter size-full wp-image-29344" title="未定名文件-1" src="/uploads/allimg/c180802/1533153Z060930-14242.png" />
各人顺着此图的干系,昆山软件开发,去看readObject要领的实现。
首先进入readObject0要领里,要害代码如下:
switch (tc) { //省略部门代码 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"); } //省略部门代码
这里就是判定方针工具的范例,差异范例执行差异的行动。我们的是个普通的Object工具,自然就是进入case TC_OBJECT的代码块中。然后进入readOrdinaryObject要领中。
readOrdinaryObject要领的代码片断:
private Object readOrdinaryObject(boolean unshared) throws IOException { //此处省略部门代码 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); } //此处省略部门代码 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) { handles.setObject(passHandle, obj = rep); } } return obj; }
重点看代码块:
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); }
这里建设的这个obj工具,就是本要领要返回的工具,也可以临时领略为是ObjectInputStream的readObject返回的工具。
isInstantiable:假如一个serializable/externalizable的类可以在运行时被实例化,那么该要领就返回true。针对serializable和externalizable我会在其他文章中先容。
desc.newInstance:该要领通过反射的方法挪用无参结构要领新建一个工具。
所以。到今朝为止,也就可以表明,为什么序列化可以粉碎单例了?即序列化会通过反射挪用无参数的结构要领建设一个新的工具。
接下来再看,为什么在单例类中界说readResolve就可以办理该问题呢?照旧在readOrdinaryObjec要领里继承往下看。
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) { handles.setObject(passHandle, obj = rep); } }
这段代码也很清楚地给出谜底了!
假如方针类有readResolve
要领,那就通过反射的方法挪用要被反序列化的类的readResolve要领,返回一个工具,然后把这个新的工具复制给之前建设的obj(即最终返回的工具)。那readResolve
要领里是什么?就是直接返回我们的单例工具。
public class Elvis implements Serializable { public static final Elvis INSTANCE = new Elvis(); private Elvis() { System.err.println("Elvis Constructor is invoked!"); } private Object readResolve() { return INSTANCE; } }