【问题标题】:Java Object Serialization nested objectsJava 对象序列化嵌套对象
【发布时间】:2013-11-27 02:30:25
【问题描述】:

我在学习 Java 中的序列化时遇到保存不可序列化且在要序列化的类(实例变量)中引用的对象的状态。在下面的代码中,我有类 Dog (Serializable),它引用了类 Collar(not serializable);它又引用了 Color 类(不可序列化)。尽管尝试了所有可能性,但我遇到了错误。这是我想出的最新代码:

class Color {
    private String colorName;

    public String getColorName() {
        return colorName;
    }

    public void setColorName(String colorName) {
        this.colorName = colorName;
    }

    Color(String color) {
        this.colorName = color;
    }
}

class Collar {

    private Color color;
    private int size;

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    Collar(int size, Color color) {
        this.size = size;
        this.color = color;
    }
}

class Dog implements Serializable {

    Dog(String breed, Collar collar) {
        this.breed = breed;
        this.collar = collar;
    }
    private String breed;

    public String getBreed() {
        return breed;
    }

    public void setBreed(String breed) {
        this.breed = breed;
    }

    public Collar getCollar() {
        return collar;
    }

    public void setCollar(Collar collar) {
        this.collar = collar;
    }
    transient private Collar collar;

    private void writeObject(ObjectOutputStream os) {
        try {
            os.defaultWriteObject();
            os.writeInt(this.getCollar().getSize());
            os.writeUTF(this.getCollar().getColor().getColorName());
            os.close();
        } catch (IOException ex) {
            Logger.getLogger(Dog.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void readObject(ObjectInputStream is) {
        try {
            is.defaultReadObject();
            int size = is.readInt();
            String colorName = is.readUTF();
            this.setCollar(new Collar(size, new Color(colorName)));
            is.close();
        } catch (Exception ex) {
            Logger.getLogger(Dog.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

public class App0001 {

    public static void main(String[] args) {

        try {
            Dog d = new Dog("Great Dane", new Collar(3, new Color("RED")));
            //System.out.println(d.getCollar().getColor().getColorName());
            ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("obj.ser"));
            os.writeObject(d);
            os.close();

            ObjectInputStream is = new ObjectInputStream(new FileInputStream("obj.ser"));
            d = (Dog) is.readObject();
            System.out.println(d.getCollar().getColor().getColorName());
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }
}

我收到以下错误:

java.io.IOException: Write error
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:260)
at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1847)
at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1756)
at java.io.ObjectOutputStream.writeNonProxyDesc(ObjectOutputStream.java:1257)
at java.io.ObjectOutputStream.writeClassDesc(ObjectOutputStream.java:1211)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1395)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.writeFatalException(ObjectOutputStream.java:1547)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:333)
at Serialization.App0001.main(App0001.java:121)

这不是生产代码。这只是为了练习和理解。

【问题讨论】:

  • 嗯。谁对此投了反对票?为什么?没有意见?实际上,我认为这个问题有它所需要的一切!它有一个简短的主题描述,它有一个问题描述,它显示异常(带有堆栈跟踪),它有代码,这只是为了这个问题而简化的。不错!

标签: java object serialization


【解决方案1】:

您不能关闭readObject 和writeObject 中的流!如果这样做,下一次写入/读取尝试将失败。

通常,流(作为其他资源)应如下处理:

  • 如果您的方法拥有流,即您的方法打开它 - 关闭它 使用相同的方法(通常在 try-with-resource statement 中完成)。
  • 如果您的方法不拥有流,即它从其他地方传递流(通常通过方法参数传递),请不要关闭它,因为您不知道流的所有者想要做什么在你的方法返回之后。

【讨论】:

  • 下一次读/写是什么意思?我只写了两个字段,流的目的就完成了。以后不写别的了。
  • 如果需要序列化多个对象怎么办?如果框架想在之后进行一些额外的写入怎么办?由于您不拥有该流,请不要关闭它!
【解决方案2】:

写入流时,如果流已关闭,则会出现IOException 中的“写入错误”。

分析您的代码,我发现您的类Dog 中有一个自定义的writeObject 方法。因为你不能关闭流,因为它是继续写入所必需的。所以只需删除该行

os.close();

在您的 writeObject 方法中。哦,还有删除线

is.close();

在readObject 方法中。


好的,我会再解释一下。您的 main 方法中有以下代码:

ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("obj.ser"));
os.writeObject(d);
os.close();

在这里,您正在创建流、使用它,然后关闭它。这是关闭它的正确位置,因为这是流的负责位置。

想象一下,您有一个可序列化对象的嵌套结构,其类定义都包含一个自定义的writeObject 方法。当调用ObjectOutputStream 的writeObject 方法时,它通过调用每个对象的writeObject 方法遍历对象图。 ObjectOutputStream 控制着写入顺序,它自己也写入控制字节。创建和关闭必须在外部完成(就像你已经做过的那样)。

【讨论】:

  • 成功了。谢谢。但是,我仍然不明白为什么不应该关闭输入和输出流。继续写是什么意思?我的意思是我正在写两个字段,就是这样。目的完成,要关闭流以节省资源。
  • 你不应该关闭输入和输出流,因为你不知道你已经完成了它们。其他人正在使用该参数调用您的方法:他们拥有流,而不是您。
猜你喜欢
  • 2017-12-28
  • 2020-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多