《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;
}
}