为什么readObject和writeObject是私有的,为什么我会明确地写出瞬态变量?

Vin*_*C M 36 java serialization effective-java

我正在阅读有效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);
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

And*_*s_D 36

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

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

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

(2)的例子只是说明如何特殊处理工作.在此示例中,size是瞬态的,不会被序列化.但是现在我们引入了特殊的处理程序,这个处理程序size为流添加了值.与非瞬态场的正常方法的不同之处可能是结果流中元素的顺序(如果它很重要......).

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


Paŭ*_*ann 17

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

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

(请注意,这仅适用于自身实现Serializable的超类.)

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

  • 相反,`super.writeObject`对我来说更有意义. (3认同)
  • @TomášZato这种方式用于实现Externalizable接口(具有公共方法)的类. (2认同)

shr*_*000 11

关于readObject()/ writeObject()是私有的,这里是交易:如果你的类Bar扩展了一些类Foo; Foo还实现了readObject()/ writeObject(),而Bar也实现了readObject()/ writeObject().

现在,当一个Bar对象被序列化或反序列化时,JVM需要自动为Foo和Bar调用readObject()/ writeObject()(即,不需要显式地对这些超类方法进行分类).但是,如果这些方法不是private,它成为方法重写,JVM不再能够调用子类对象上的超类方法.

因此他们必须是私人的!


Sak*_*ket 7

readObjectwriteObject被调用的Object(Input/Output)Stream类(ES).

这些方法是(并且必须)声明为私有(在实现自己的时),证明/指示这两种方法都不被实现继承和覆盖或重载.这里的技巧是JVM自动检查是否在相应的方法调用期间声明了任一方法.请注意,JVM可以随时调用类的私有方法,但没有其他对象可以.因此,保持了类的完整性,并且序列化协议可以继续正常工作.

关于瞬态int,它只是控制整个对象序列化的序列化.但请注意,从技术上讲,如果所有字段都是瞬态的,则甚至不需要调用defaultWriteObject().但我认为仍然建议为灵活性目的调用它,以便以后可以在类中引入非瞬态成员,从而保持兼容性.

  • 这些方法不是"对象(输入/输出)流"的一部分,它们是需要特殊处理序列化/反序列化的"Serializable"类所必需的.流类中的`readObject()`和`writeObject(Object obj)`是`public final`. (2认同)