为什么 readObject 和 writeObject 是私有的,为什么我要显式编写瞬态变量?

2022-09-01 03:42:35

我正在阅读关于有效Java中的序列化的章节。

  1. 谁调用 readObject() 和 writeObject()?为什么这些方法被声明为私有?

  2. 以下是书中的一段代码

    // StringList with a reasonable custom serialized form
    public final class StringList implements Serializable {
        private transient int size = 0;
        private transient Entry head = null;
    
        //Other code
    
        private void writeObject(ObjectOutputStream s)
            throws IOException {
            s.defaultWriteObject();
            s.writeInt(size);
            // Write out all elements in the proper order.
            for (Entry e = head; e != null; e = e.next)
               s.writeObject(e.data);
            }
        }
    }
    

    是否有任何特定原因将变量声明为瞬态,然后在 writeObject 方法中显式写入它?如果它没有被宣布为瞬态,它无论如何都会被写出来,对吧?size


答案 1

(1) 这些方法未在任何类或接口中声明。实现接口并在序列化和反序列化过程中需要特殊处理的类必须实现这些方法,并且序列化程序/反序列化程序将尝试反映这些方法。Serializable

这是Java中相当奇怪的角落之一,其中API实际上是在javaDoc中定义的...但是,如果这些方法已经在接口中定义,那么它们必须是(我们不能通过添加修饰符来实现接口方法锁定它)。publicprivate

为什么私有 - javaDoc没有给出提示。也许它们被指定为私有,因为除了实现器之外没有其他类打算使用它们。根据定义,它们是私有的

(2) 该示例仅显示了特殊处理的工作原理。在此示例中,是暂时性的,不会进行序列化。但现在我们引入特殊的处理程序,这个处理程序将 的值添加到流中。与具有非瞬态字段的正常方法的不同之处可能是结果流中元素的顺序(如果它很重要...)。sizesize

如果在超类中定义了瞬态字段,并且子类想要序列化该值,则该示例可能很有意义。


答案 2

除了不应该被错误的一方使用之外,以下是这些方法的隐私的另一个原因:

我们不希望这些方法被子类覆盖。相反,每个类都可以有自己的方法,序列化引擎将一个接一个地调用所有这些类。这只能通过私有方法实现(这些方法不会被覆盖)。(这同样适用于 。)writeObjectreadObject

(请注意,这仅适用于本身实现可序列化的超类。

这样,子类和超类可以独立发展,并且仍然与旧版本中的存储对象保持兼容。