有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

序列化从更改的类读取的序列化对象的Java兼容性

我有一个这样的班级:

public class Foo implements Serializable {

    private static final long serialVersionUID = 20130605L;

    private Object fields[];

    // Methods, etc.
}

有一段时间这还可以,但现在(为了可读性和维护)已经转变为:

public class Foo implements Serializable {

    private static final long serialVersionUID = 20130605L;

    private String field1;
    private String field2;
    private Boolean fiedl3;

    // Methods, etc.
}

当你用新的类版本阅读旧文件时,问题就来了。如果使用不同的serialVersionUID,则不兼容。如果您使用相同的serialVersionUID,我需要实现一些东西使其兼容。这是我的建议,覆盖private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException,这样我可以手动检查文件中的对象是什么版本

问题再次出现,我想使用java.io.ObjectInputStream.defaultReadObject();,所以它会自动为下一个版本发挥“魔力”(在witch中,新字段将是可选的)。所以我有点像:

public class Foo implements Serializable {

    private static final long serialVersionUID = 20130605L;

    private String field1;
    private String field2;
    private Boolean fiedl3;

    // Methods, etc.

    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {


        Object obj = in.readObject();

            if (obj instanceof Object[]) {
            Object[] tmp = (Object[])obj;
            field1 = (String)obj[0];
            field2 = (String)obj[1];
            // ....
        } else {
            in.defaultReadObject();
        }
    }
}

问题是,由于我已经读取了部分流,defaultReadObject方法崩溃了

我搜索了一条流,它可以让你读取一个对象两次,但我没有找到它。我也知道我可以完全手动读取,但每次添加另一个字段时,我都需要修改它(在defaultReadObject中,当它写入字段名称时,它只能恢复自动读取的字段)

所以我的问题是,我怎样才能做到

注意:我只需要兼容性是从新类读取旧类对象和从新类对象读取新类对象。我也读过其他的问题,但他们只回答了如何计划一个好的类,使其具有backguard兼容性(我以前应该读过:-())


共 (1) 个答案

  1. # 1 楼答案

    我找到的唯一解决方案是保留对旧字段的引用。请注意,您可以将其设置为transient,因为这样它就不会被读取,所以您必须永远携带它

    public class Foo implements Serializable {
    
        private static final long serialVersionUID = 20130605L;
    
        private Object fields[]; // So we can read it in old saved version.
    
        private String field1;
        private String field2;
        private Boolean fiedl3;
    
        // Methods, etc.
    
        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
    
    
            in.defaultReadObject();
    
    
            if (fields != null) {
                // If we have read an old version.
                field1 = (String)fields[0];
                field2 = (String)fields[1];
                field3 = (Boolean)fields[2];
                // ....
    
                // We set fields to null so no more space is waste than necessary.
                fields = null;
            }
    
        }
    }