1.显式声明UID
如果不显式声明,生产者和消费者的字段不一样的时候,JVM根据类名,参数等自动生成的序列就会不一样,会报InvaidClassException,但是如果双方显式声明serialVerisonUID 就不会。
显式声明serialVersionUID可以避免对象不一致,但尽量不要以这种方式向JVM“撒谎”。
2.在序列化类中,不使用构造函数为final变量赋值
当序列化UID不变的时候,反序列化时,构造函数不会执行。所以改变赋值却不会生效。
总结,反序列化时final变量在以下情况不会被重新赋值:
1.通过构造函数为final变量赋值
2.通过方法返回值为final变量赋值
3.final修饰的属性不是基本类型
So,避免为final变量复杂赋值
3.使用序列化类的私有方法,巧妙解决部分属性持久化问题
例如属于场景:
有一个计税系统和HR系统,计税系统需要从HR系统中获取人员的姓名和基本工资,而HR系统工资包括基本工资和奖金,奖金属于个人隐私,不能泄露给外系统。
Salary设计如下:
public class Salary implements Serializable {
private static final long serialVersionUID = 1L;
private int basePay;
private transient int bonus;
public Salary(int _basePay, int _bonus) {
basePay = _basePay;
bonus = _bonus;
}
省略set,get方法
}
Person设计如下:
public class Person implements Serializable {
private static final long serialVersionUID = 2L;
private String name;
private Salary salary;
public Person(String _name, Salary _salary) {
name = _name;
salary = _salary;
}
省略set,get方法
}
反序列化代码如下:
public class Customer {
public static void main(String[] args){
Person person =(Person)SerializationUtils.readObject();
StringBuffer stringBuffer=new StringBuffer();
stringBuffer.append("name....."+person.getName());
stringBuffer.append("\tbasePay....."+person.getSalary().getBasePay());
stringBuffer.append("\tbonus....."+person.getSalary().getBonus());
System.out.println(stringBuffer);
}
}
打印如下:
name…张静 basePay…1000 bonus…2500
显然不符合要求。
改进方案
1.在bonus字段前加transient,使得Salary类失去分布部署的功能
2.再增加额外的对象只包括姓名和基本工资,但增加了代码量
3.请求时候过滤,不符合日常设计
4.用XML传输,成本太高
比较好的方法
改造Person类,实现Serialzable接口的两个私有的方法:writeObject和readObject,影响和控制序列化和反序列化过程。
private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();
out.writeObject(salary.getBasePay());
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
salary=new Salary(in.readInt(),0);
}