紧接着上一篇,我们来看看另一个
序列化类JavaSerializer。
这个类一般是用来序列化我们
自定义类的,所以更多的时候我们用到的是它,今天
打算分析两个方面,第一是JavaSerializer本身实现,第二分析下反序列化的时候为什么会存在父类同名field值覆盖子类field问题
1.JavaSerializer实现
// 首先看一下JavaSerializer的构造方法
public JavaSerializer(Class cl, ClassLoader loader)
{
...
// 存放简单类型字段
ArrayList primitiveFields = new ArrayList();
// 存放复杂类型字段
ArrayList compoundFields = new ArrayList();
// 获取子类到父类所有field字段
for (; cl != null; cl = cl.getSuperclass()) {
Field []fields = cl.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
// 过滤掉这两种类型的field
if (Modifier.isTransient(field.getModifiers())
|| Modifier.isStatic(field.getModifiers()))
continue;
field.setAccessible(true);
// 按类型存入arrayList
if (field.getType().isPrimitive()
|| (field.getType().getName().startsWith("java.lang.")
&& ! field.getType().equals(Object.class)))
primitiveFields.add(field);
else
compoundFields.add(field);
}
}
// 合并成一个list并转换成数组 (ps: 这样看来之前用两个list来存放似乎没有什么意义?!)
ArrayList fields = new ArrayList();
fields.addAll(primitiveFields);
fields.addAll(compoundFields);
_fields = new Field[fields.size()];
fields.toArray(_fields);
_fieldSerializers = new FieldSerializer[_fields.length];
// 获取每一个field对应的FieldSerializer(注1)
for (int i = 0; i < _fields.length; i++) {
_fieldSerializers[i] = getFieldSerializer(_fields[i].getType());
}
}
接着我们看下JavaSerializer的writeObject方法:
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException
{
...
Class cl = obj.getClass();
...
// 写类头,输出格式: 'Mt'[类名长度][类名]
int ref = out.writeObjectBegin(cl.getName());
// 对于HessianOutput 总是返回-2
if (ref < -1) {
writeObject10(obj, out);
}
else {
if (ref == -1) {
writeDefinition20(out);
out.writeObjectBegin(cl.getName());
}
writeInstance(obj, out);
}
}
private void writeObject10(Object obj, AbstractHessianOutput out)
throws IOException
{
// 循环序列化该类的field(先子类后父类)
for (int i = 0; i < _fields.length; i++) {
Field field = _fields[i];
// 序列化field名
out.writeString(field.getName());
// 序列化field值
_fieldSerializers[i].serialize(out, obj, field);
}
// 结束标记 'z'
out.writeMapEnd();
}
以上是JavaSerializer的基本实现,在(注1)有这么一段代码:
for (int i = 0; i < _fields.length; i++) {
_fieldSerializers[i] = getFieldSerializer(_fields[i].getType());
}
我们看下可以获取哪些FieldSerializer,以及它们究竟是如何工作的?
private static FieldSerializer getFieldSerializer(Class type)
{
// 对于简单类型的处理
if (int.class.equals(type)
|| byte.class.equals(type)
|| short.class.equals(type)
|| int.class.equals(type)) {
return IntFieldSerializer.SER;
}
else if (long.class.equals(type)) {
return LongFieldSerializer.SER;
}
else if (double.class.equals(type) ||
float.class.equals(type)) {
return DoubleFieldSerializer.SER;
}
else if (boolean.class.equals(type)) {
return BooleanFieldSerializer.SER;
}
else if (String.class.equals(type)) {
return StringFieldSerializer.SER;
}
else if (java.util.Date.class.equals(type)
|| java.sql.Date.class.equals(type)
|| java.sql.Timestamp.class.equals(type)
|| java.sql.Time.class.equals(type)) {
return DateFieldSerializer.SER;
}
// 对于复杂类型的处理
else
// 所有其他类型field(比如自定义类) 就使用默认FieldSerializer
return FieldSerializer.SER;
}
现在我们具体看下这些FieldSerializer(比较容易,不多解释)
static class BooleanFieldSerializer extends FieldSerializer {
static final FieldSerializer SER = new BooleanFieldSerializer();
void serialize(AbstractHessianOutput out, Object obj, Field field)
throws IOException
{
boolean value = false;
try {
value = field.getBoolean(obj);
} catch (IllegalAccessException e) {
log.log(Level.FINE, e.toString(), e);
}
out.writeBoolean(value);
}
}
static class IntFieldSerializer extends FieldSerializer {
static final FieldSerializer SER = new IntFieldSerializer();
void serialize(AbstractHessianOutput out, Object obj, Field field)
throws IOException
{
int value = 0;
try {
value = field.getInt(obj);
} catch (IllegalAccessException e) {
log.log(Level.FINE, e.toString(), e);
}
out.writeInt(value);
}
}
static class FieldSerializer {
static final FieldSerializer SER = new FieldSerializer();
void serialize(AbstractHessianOutput out, Object obj, Field field)
throws IOException
{
Object value = null;
try {
value = field.get(obj);
} catch (IllegalAccessException e) {
log.log(Level.FINE, e.toString(), e);
}
try {
out.writeObject(value); // 这里是怎么做的? 是不是又回到了上一节? ^_^
} catch (RuntimeException e) {
throw new RuntimeException(e.getMessage() + "\n Java field: " + field, e);
} catch (IOException e) {
throw new IOExceptionWrapper(e.getMessage() + "\n Java field: " + field, e);
}
}
}
剩余的XxxFieldSerializer我就不在赘述,基本和前面一致,之前
我自己看源码看到这里,我就有一个疑问,其实对于所有的Field都可以返回FieldSerializer而不必那么细致区分返回IntFieldSerializer, StringFieldSerializer等等,但是作者这里为什么还要这么做呢?
我自己的回答是加快序列化速度,不然对于每一个field 都需要走上一节说的流程,这只是我的一己之见,希望各位也能谈谈自己看法。
2.之前在文章开始,我提到在序列化的时候存在父类覆盖子类同名field的情况,现在我们就来看下源码,分析下为什么会出现这样的情况?(只是谈谈自己看法,若是有不对的地方,还希望各位能够提点一下,^_^)
JavaSerializer的实现我们前面已经分析,现在我们分析下JavaDeSerializer的实现(关键就在于序列化和反序列化的不一致引起的)
public JavaDeserializer(Class cl)
{
...
// 最关键的一段代码
_fieldMap = getFieldMap(cl);
...
}
我们看下getFieldMap(cl)的实现:
protected HashMap getFieldMap(Class cl)
{
// 创建一个hashmap存放field (有没有觉得和JavaSerializer不一致,JavaSerializer是把field存放到一个list中去)
HashMap fieldMap = new HashMap();
// 循环读取从子类到父类的field
for (; cl != null; cl = cl.getSuperclass()) {
Field []fields = cl.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (Modifier.isTransient(field.getModifiers()) ||
Modifier.isStatic(field.getModifiers()))
continue;
// 重点!!!! 由于是从子类循环到父类,所以若是存在同名字段,fieldMap中放的都是子类字段!!!!
else if (fieldMap.get(field.getName()) != null)
continue;
try {
field.setAccessible(true);
} catch (Throwable e) {
e.printStackTrace();
}
Class type = field.getType();
FieldDeserializer deser;
if (String.class.equals(type))
deser = new StringFieldDeserializer(field);
else if (byte.class.equals(type)) {
deser = new ByteFieldDeserializer(field);
}
else if (short.class.equals(type)) {
// 省略
}
else {
deser = new ObjectFieldDeserializer(field);
}
fieldMap.put(field.getName(), deser);
}
}
return fieldMap;
}
从上面代码我们得出一个结论:对于同名字段fieldMap中存放的是子类field; 另外在序列化的时候,对于同名field是子类值在前,父类值在后,于是赋值就变成:子类值->子类field, 父类值->子类field 所以就发生了值覆盖问题!