如果您想进行不兼容的更改,您应该更改serialVersionUID,这样您会得到一个适当的(如果不是很好)错误,而不是在某个时候出现ClassCastException。
如果要保持兼容性,请保留serialVersionUID 并添加自定义readObject 方法将List<CharSequence> 转换为List<String>。
编辑:进一步扩展,如果你想要兼容性,你的代码应该是这样的:
// final - for one thing I don't want to implement readObjectNoData
public final class JeanObject {
如果这个类作为子类添加到另一个类中,那么遗留的序列化流中将“没有数据”。
private static final long serialVersionUID = 1L;
// Mutable field for Java Serialization, but treat as final.
private List<String> values = new ArrayList<>();
如果您希望values 成为final,您将需要一个退化的序列化代理 hack,其中代理对象属于同一类型。
我假设您希望集合对象是可变的。您可能不应该序列化可变对象,但这就是它通常的使用方式以及 OP 示例的感觉。
private void readObject(
ObjectInputStream in
) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields = in.readFields();
@SuppressWarnings("unchecked")
var oldValues = (List<CharSequence>)fields.get("values", null);
// Don't bother with nice error message.
// NPE if missing or null elements.
this.values = oldValues.stream().collect(
ArrayList::new,
(values, value) -> values.add(value.toString()),
List::addAll
);
}
// ...
(非常功能性)3-arg Stream.collect 的替代方法是使用Collectors.mapping。老式的豪华 for 循环会全面减少混乱,但这并没有在互联网上炫耀 - 你看起来像一个只是完成工作的人。
Collectors.toList 可能不适合,例如,将元素添加到列表中可能会导致错误。也许不是今天。也许不是明天。但是当你的继任者自动更新实现时。他们会恨你一辈子。以下是 API 文档:
不保证类型、可变性、可序列化或
List 的线程安全返回
谁想要那个?
编辑:再次阅读该引用,如果您使用 toList...,您可能无法序列化您的反序列化对象...
(代码可以编译,但与以往一样,未经测试。)