Java泛型在类字段和序列化上发生更改

Java泛型在类字段和序列化上发生更改,java,serialization,Java,Serialization,我有一个Java序列化问题,在Java文档(for)中既没有被报告也没有被否定为有问题 因此,假设我有一个实现Serializable private static final long serialVersionUID = 1L; private List<CharSequence> values; 我是否应该更改serialVersionUID?完全由您决定。当您指定serialVersionUID时,您将承担在需要时更改它的责任。 如果您的系统在需要更改此对象时有遇到此对象

我有一个Java序列化问题,在Java文档(for)中既没有被报告也没有被否定为有问题

因此,假设我有一个实现
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-arg
Stream.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
        );
    }
    // ...