项目使用的是蚂蚁的SOFARPC,序列化方式使用的是Hessian,有一次一个类继承父类,但是子类中也写了一个和父类一样的属性,导致取值时,该属性的值为空
事例代码
public static void main(String[] args) throws IOException {
UserInfo user = new UserInfo();
user.setUsername("hello world");
user.setPassword("buzhidao");
user.setAge(21);
ByteArrayOutputStream os = new ByteArrayOutputStream();
//Hessian的序列化输出
HessianOutput ho = new HessianOutput(os);
ho.writeObject(user);
byte[] userByte = os.toByteArray();
ByteArrayInputStream is = new ByteArrayInputStream(userByte);
//Hessian的反序列化读取对象
HessianInput hi = new HessianInput(is);
UserInfo u = (UserInfo) hi.readObject();
System.out.println("姓名:" + u.getUsername());
System.out.println("年龄:" + u.getAge());
}
static class User implements Serializable{
private String username ;
private String password;
private Integer age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
static class UserInfo extends User{
private String username;
@Override
public String getUsername() {
return username;
}
@Override
public void setUsername(String username) {
this.username = username;
}
}
输出结果:
姓名:null
年龄:21
导致这种结果的原因
-
- hessian序列化的时候会取出对象的所有自定义属性,相同类型的属性是子类在前父类在后的顺序。
-
- hessian在反序列化的时候,是将对象所有属性取出来,存放在一个map中 key = 属性名 value是反序列类,相同名字的会以子类为准进行反序列化。
-
- 相同名字的属性 在反序列化的是时候,由于子类在父类前面,子类的属性总是会被父类的覆盖,由于java多态属性,在上述例子中父类 User.username = null
源码分析
1、序列化 当序列化对象是一个java自定对象时,默认的序列化类是 UnsafeSerializer,调用writeObject
public void writeObject(Object object)
throws IOException {
if (object == null) {
writeNull();
return;
}
Serializer serializer;
serializer = _serializerFactory.getSerializer(object.getClass());
serializer.writeObject(object, this);
}
2、反序列化
到这里我们看这三个属性还是有值的,但是输出就没有值了, 由于名字相同的属性,反序列化是第一个子类,往后父类的发现map中有就会忽略,所以在属性序列化的时候,先序列化子类的,接着是父类的,但是他们在对象中的偏移量是一样的(用的是同一个反序列化类),所以相同名字的属相,子类总是会被父类覆盖掉。