1700439112
1700439113
/*其他保持不变*/
1700439114
1700439115
}
1700439116
1700439117
刚开始生产者和消费者持有的Person类版本一致,都是V1.0,某天生产者的Person类版本变更了,增加了一个“年龄”属性,升级为V2.0,而由于种种原因(比如程序员疏忽、升级时间窗口不同等)消费端的Person还保持为V1.0版本,代码如下:
1700439118
1700439119
public class Person implements Serializable{
1700439120
1700439121
private static final long serialVersionUID=5799L;
1700439122
1700439123
private int age;
1700439124
1700439125
/*age、name的getter/setter方法省略*/
1700439126
1700439127
}
1700439128
1700439129
此时虽然生产者和消费者对应的类版本不同,但是显式声明的serialVersionUID相同,反序列化也是可以运行的,所带来的业务问题就是消费端不能读取到新增的业务属性(age属性)而已。
1700439130
1700439131
通过此例,我们的反序列化实现了版本向上兼容的功能,使用V1.0版本的应用访问了一个V2.0版本的对象,这无疑提高了代码的健壮性。我们在编写序列化类代码时,随手加上serialVersionUID字段,也不会给我们带来太多的工作量,但它却可以在关键时候发挥异乎寻常的作用。
1700439132
1700439133
注意 显式声明serialVersionUID可以避免对象不一致,但尽量不要以这种方式向JVM“撒谎”。
1700439134
1700439135
1700439136
1700439137
1700439139
编写高质量代码:改善Java程序的151个建议 建议12:避免用序列化类在构造函数中为不变量赋值
1700439140
1700439141
我们知道带有final标识的属性是不变量,也就是说只能赋值一次,不能重复赋值,但是在序列化类中就有点复杂了,比如有这样一个类:
1700439142
1700439143
public class Person implements Serializable{
1700439144
1700439145
private static final long serialVersionUID=71282334L;
1700439146
1700439147
//不变量
1700439148
1700439149
public fnal String name=“混世魔王”;
1700439150
1700439151
}
1700439152
1700439153
这个Person类(此时V1.0版本)被序列化,然后存储在磁盘上,在反序列化时name属性会重新计算其值(这与static变量不同,static变量压根就没有保存到数据流中),比如name属性修改成了“德天使”(版本升级为V2.0),那么反序列化对象的name值就是“德天使”。保持新旧对象的final变量相同,有利于代码业务逻辑统一,这是序列化的基本规则之一,也就是说,如果final属性是一个直接量,在反序列化时就会重新计算。对这基本规则不多说,我们要说的是final变量另外一种赋值方式:通过构造函数赋值。代码如下:
1700439154
1700439155
public class Person implements Serializable{
1700439156
1700439157
private static final long serialVersionUID=91282334L;
1700439158
1700439159
//不变量初始不赋值
1700439160
1700439161
public final String name;
[
上一页 ]
[ :1.700439112e+09 ]
[
下一页 ]