4

当我遇到保存不可序列化并且在要序列化的类(实例变量)中引用的对象的状态时,我正在研究 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)

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

4

2 回答 2

2

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

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

  • 如果您的方法拥有流,即您的方法打开它 - 以相同的方法关闭它(通常在try-with-resource 语句中完成)。
  • 如果您的方法不拥有流,即它从其他地方传递了流(通常通过方法参数传递),请不要关闭它,因为您不知道流的所有者在您之后想要对它做什么方法返回。
于 2013-11-14T07:10:41.283 回答
1

写入流IOException时,如果流已关闭,则会发生“写入错误”。

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

os.close();

在你的writeObject方法中。哦,还要删除线

is.close();

readObject方法中。


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

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

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

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

于 2013-11-14T07:15:36.087 回答