我有一个Java序列化问题,在Java Docs中(JDK8)既没有报告也没有否认它有问题。
因此,假设我有一个实现Serializable
private static final long serialVersionUID = 1L;
private List<CharSequence> values;
如果我将values
更改为
private List<String> values;
我应该更改serialVersionUID
吗?
答案 0 :(得分:4)
考虑此序列化/反序列化操作的另一种方法是,它有点像强制转换。
您可以将List<CharSequence>
投射到List<String>
吗?不直接:编译器会阻止您,因为泛型是不变的。您可以强制执行此操作,
List<String> list = (List<String>) (List<?>) listOfCharSequences;
String entry = list.get(0);
并且此可能经常工作,因为String
是最常见的CharSequence
。
但是其中可能还有其他CharSequence
,而不是String
,例如StringBuilder
。上面的代码将以ClassCastException
崩溃。
因此,如果您可以确定所有CharSequence
都是真实的String
,则可以安全地进行此更改。否则,您应该通过更改串行版本ID来防止它;或者或者,对于String
,您可以简单地在所有元素上调用toString()
:
List<String> listOfStrings = listOfCharSequences.stream()
.map(cs -> Objects.toString(cs, null))
.collect(toList())
({String.toString()
返回自身,因此对于已经String
s的元素,这将不返回新实例)
答案 1 :(得分:2)
如果您要进行不兼容的更改,则应更改serialVersionUID
,这样您将得到一个适当的(如果不是很好的)错误,而不是某个以后的ClassCastException
。 / p>
如果要保持兼容性,请保留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 loop不会造成混乱,但这在Internet上并没有炫耀-您看起来就像是刚刚完成工作的人。
Collectors.toList
可能不适合,例如,在行的某个位置向列表中添加元素可能会导致错误。也许不是今天。也许不是明天。但是当您的后继者自动更新实现时。他们将一生都讨厌您。 API文档讨论如下:
不保证类型,可变性,可序列化性或 返回的
List
的线程安全性
谁想要的?
编辑:再次阅读该报价,如果您使用toList
...
(代码可以编译,但是仍然未经测试。)
答案 2 :(得分:-2)
完全取决于您。当您指定serialVersionUID时,您将负责在需要时进行更改。 如果您的系统在需要更改此对象时有遇到不同版本的风险。