【问题标题】:Java serialization of transient fields瞬态字段的Java序列化
【发布时间】:2011-04-15 20:54:39
【问题描述】:

我正在阅读 Thinking in Java 4th Edition。 那里描述了transient 字段序列化的奇怪解决方法:

import java.io.*;

public class SerializationTest implements Serializable {
    private String firstData;
    //transient field, shouldn't be serialized.
    transient private String secondData;

    public SerializationTest(String firstData, String test2) {
        this.firstData = firstData;
        this.secondData = test2;
    }

    /**
     * Private method, same signature as in Serializable interface
     *
     * @param stream
     * @throws IOException
     */
    private void writeObject(ObjectOutputStream stream) throws IOException {
        stream.defaultWriteObject();
        stream.writeObject(secondData);
    }

    /**
     * Private method, same signature as in Serializable interface
     *
     * @param stream
     * @throws IOException
     */
    private void readObject(ObjectInputStream stream)
            throws IOException, ClassNotFoundException {
        stream.defaultReadObject();
        secondData = (String) stream.readObject();

    }

    @Override
    public String toString() {
        return "SerializationTest{" +
                "firstData='" + firstData + '\'' +
                ", secondData='" + secondData + '\'' +
                '}';
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        FileOutputStream fos = null;
        ObjectOutputStream oos = null;
        try {
            fos = new FileOutputStream("object.out");
            oos = new ObjectOutputStream(fos);
            SerializationTest sTest = new SerializationTest("First Data", "Second data");
            oos.writeObject(sTest);
        } finally {
            oos.close();
            fos.close();
        }
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        try {
            fis = new FileInputStream("object.out");
            ois = new ObjectInputStream(fis);
            SerializationTest sTest = (SerializationTest) ois.readObject();
            System.out.println(sTest);
        } finally {
            ois.close();
            fis.close();
        }
        //Output:
        //SerializationTest{firstData='First Data', secondData='Second data'}
    }
}

如您所见,实现了私有方法writeObjectreadObject

问题是:

ObjectOutputStream 和 ObjectInputStream 使用反射访问私有方法的原因是什么?

Java 中包含多少这样的后门?

【问题讨论】:

  • 顺便说一句,您的资源处理不正确。标准格式为:Resource resource = acquire(); try { use(resource); } finally { resource.release(); }。您应该为每个资源单独执行此操作。在 Java SE 6 中,大多数情况下您可以编写 try (Resource resource = acquire()) { use(resource); }。没有必要关闭你的对象流,除了只在快乐的情况下刷新ObjectOutputStream(也就是说在try的主体中;在finally中刷新也会在错误情况下这样做,这并不是你真正想要的)。
  • @Tom:try(...){ 语法已经在 J​​ava SE 6 中了?这对我来说是新的,我以为只有 7 个。
  • @Paŭlo Ebermann 错字。应阅读“在 Java SE 7 中”。 (而且你不应该使用-target 1.6 -source 1.7。除了目标需要至少与源一样最新的规则之外,它还需要额外的库支持。也许 Retroweaver 或类似的东西会破解。)

标签: java serialization reflection


【解决方案1】:

后门?它一直在规范中。这是实现对象非默认序列化的唯一方法。

非默认序列化使您处于序列化驱动程序的位置。您可以将任何内容写入输出流,只要您可以将其读回并在流的另一端构造对象,就可以了。

这个人决定序列化瞬态字段的事实不是问题,关键是如果你正在实现自己的序列化方案,你可以做任何你想做的事情。

【讨论】:

    【解决方案2】:

    呃,它不是“后门”……您实现了一个自定义序列化,在调用忽略它们的默认序列化后将瞬态字段输出到输出流。

    【讨论】:

      【解决方案3】:

      Serializable 接口是标记接口。所以它就像一个标签来解释java编译器。还有其他标记接口,如 Clonable 等。有关更多信息,请参阅here。 不过现在@annotations 被更多人使用了。

      【讨论】:

        猜你喜欢
        • 2012-03-30
        • 2021-04-22
        • 1970-01-01
        • 2018-09-23
        • 2016-07-01
        • 1970-01-01
        • 2017-03-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多