2.8 序列化:完整版
2.1.3 节列出了实现序列化的五个步骤,到现在为止,我们已经可以借助 Field
对象实现这五个任务了。下面是完整版的 serializeObject
方法的实现,代码依赖 JDOM
库来处理 XML 相关内容。
private static Document serialize(Object source, Document target, IdentityHashMap<Object, Object> table) throws IllegalArgumentException, IllegalAccessException {
// 1. 创建序列化对象的 唯一标识符
String id = Integer.toString(table.size());
table.put(source, id);
Class sourceClass = source.getClass();
// 2. 为 source 对象创建 XML 元素,并添加进 root 元素 <serialized /> 中
Element objElement = new Element("object");
objElement.setAttribute("class", sourceClass.getName());
objElement.setAttribute("id", id);
target.getRootElement().addContent(objElement);
// 3. 数组需要特殊处理
if (sourceClass.isArray()) {
Class componentType = sourceClass.getComponentType();
int len = Array.getLength(source);
objElement.setAttribute("length", Integer.toString(len));
for (int i = 0; i < len; i ++) {
objElement.addContent(serializeVariable(componentType, Array.get(source, i), target, table));
}
} else {
Field [] fields = Util.getInstanceVariables(source);
for (Field f : fields) {
// non public field
if (! Modifier.isPublic(f.getModifiers())) {
f.setAccessible(true);
}
// 唯一标识符:声明类 + 字段名
Element fieldEle = new Element("field");
fieldEle.setAttribute("name", f.getName());
fieldEle.setAttribute("declaringClass", f.getDeclaringClass().getName());
Class fieldType = f.getType();
Object child = f.get(source);
if (! Modifier.isTransient(f.getModifiers())) {
child = null;
}
fieldEle.addContent(serializeVariable(fieldType, child, target, table));
objElement.addContent(fieldEle);
}
}
return target;
}
代码解析
IdentityHashMap
- 记录对象 引用次数 需要用
IdentityHashMap
,而不能用普通Map
实现、 IdentityHashMap
比较key
是否相等时,使用==
,即key
的引用相等,即认为key-value
相等,在 JVM 中,若两个key
引用相同Class
的对象,则其 引用相等。IdentityHashMap
中key
可以重复。
- 记录对象 引用次数 需要用
- 代码中用
IdentityHashMap
存储 所有对象 的引用,保证无论 对象被引用多少次,该对象仅序列化一次。