Java泛型在类字段和序列化上发生更改
我有一个Java序列化问题,在Java文档(for)中既没有被报告也没有被否定为有问题 因此,假设我有一个实现Java泛型在类字段和序列化上发生更改,java,serialization,Java,Serialization,我有一个Java序列化问题,在Java文档(for)中既没有被报告也没有被否定为有问题 因此,假设我有一个实现Serializable private static final long serialVersionUID = 1L; private List<CharSequence> values; 我是否应该更改serialVersionUID?完全由您决定。当您指定serialVersionUID时,您将承担在需要时更改它的责任。 如果您的系统在需要更改此对象时有遇到此对象
Serializable
private static final long serialVersionUID = 1L;
private List<CharSequence> values;
我是否应该更改
serialVersionUID
?完全由您决定。当您指定serialVersionUID时,您将承担在需要时更改它的责任。
如果您的系统在需要更改此对象时有遇到此对象的各种版本的风险。考虑此序列化/反序列化操作的另一种方式是,它有点像强制转换 你能把
列表
转换成列表
吗?不直接:编译器将阻止您,因为泛型是不变的。但是,您可以强制执行以下操作:
List<String> list = (List<String>) (List<?>) listOfCharSequences;
String entry = list.get(0);
(
String.toString()
返回自身,因此这将不会为已经是String
s的元素返回新实例)如果要进行不兼容的更改,则应更改serialVersionUID
,以便获得适当的(如果不好的话)错误,而不是,一个ClassCastException
在后面的某个地方
如果要保持兼容性,请保留serialVersionUID
,并添加自定义readObject
方法,以将列表
转换为列表
编辑:若要扩展此功能,若要实现兼容性,代码应如下所示:
// 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<>();
3-argStream.collect
的另一种替代方法是使用collector.mapping
。一个老式的时髦的循环会让人不那么困惑,但这并不是在互联网上炫耀——你看起来就像一个只会把事情做完的人
Collectors.toList
可能不合适,比如说,将元素添加到行的某个位置可能会导致错误。也许今天不行。也许明天不行。但当您的继任者自动更新实现时。他们会恨你一辈子。以下是API文档的内容:
对于类型、可变性、序列化性或
返回的列表的线程安全性
谁想要这个?
编辑:再次阅读该引用,如果使用toList
,可能无法序列化反序列化对象
(代码可以编译,但仍然没有经过测试。)可能有人在列表中用非字符串实例序列化了实例。所以,是的。为什么需要在文档中明确提到这一点?请参考duplicate@QingfeiYuan我不同意。答案指向我提到的Oracle的相同文档。关于泛型的变化什么都没说。@AndyTurner是的,我明白了。因此,在运行时反序列化将失败得很惨。相反的呢?那么,如果我从List
更改为List
,这是一个超类型吗?它应该能正常工作?我同意,谢谢你的澄清。你认为相反的方法会起作用吗?那么,将字段从一个类型更改为它的超类型?@JeanValjean这取决于运行旧版本代码的东西是否会读取新版本代码编写的实例。这基本上与原始问题的情况相同:如果任何期望字符串的内容读取其他内容,它将中断。
// 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<>();
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
);
}
// ...