我在一些代码上运行findbugs并且它说readObject(...)方法必须是私有的才能被调用以进行序列化/反序列化?为什么?如果将其公开,会出现什么问题?
答案 0 :(得分:6)
关于readObject()/writeObject()
私有,这是交易:如果你的班级延伸了一些类Foo; Foo还实现了readObject()/writeObject()
,Bar也实现了readObject()/writeObject()
。
现在,当一个Bar对象被序列化或反序列化时,JVM需要自动为Foo和Bar调用readObject()/writeObject()
(即,不需要显式调用这些超类方法)。但是,如果这些方法不是私有的,那么它将成为方法重写,并且JVM不能再调用子类对象上的超类方法。
因此他们必须是私人的!
答案 1 :(得分:3)
在现代Java实现中(至少JDK 6到10),ObjectInputStream
和ObjectOutputStream
类只能识别readObject
,readObjectNoData
和writeObject
方法,如果它们被声明为private
而非static
。
(我在任何文档中都没有明确说明这一点,但是在代码中明确地实现了限制。)
因此,无论是否是一个好主意,FindBugs都指出非私有readObject
方法是一个错误。它不会被使用。
我想让这个方法公开的唯一原因是让它成为最终的,这样继承对象就无法摆弄它。
我认为你不应该尝试来做到这一点。在类级别的javadoc中添加一个注释,说明您认为子类应该和不应该做什么。如果有人选择实施忽略该建议的课程,那么处理后果是他们的问题。
试图强迫其他人以特定方式实现子类的问题在于,他们可能有一个用例要求他们以不同方式执行操作...原因是你不是能够理解。让未来的开发人员自由地做他们想做的事情是一个更好的主意,让他们对后果承担责任。
答案 2 :(得分:1)
我不确定为什么findbugs认为这是一个错误,但我猜可能有两个原因。使readObject公开打破封装,因为调用代码可以看到类的内部结构。此外,通过将其公开,您强制所有派生类将readObject声明为public。因此,除非该类是最终的,否则您将更改序列化合同。
我认为findbugs可以为其大部分消息提供理由。这有什么可说的吗?
答案 3 :(得分:1)
您没有理由自己调用readObject
等序列化方法,更不用说来自另一个类了。你应该尽可能减少所有事情的可见度。
编辑:如果您希望子类能够更改行为,请创建方法protected
......这是可以接受的。
答案 4 :(得分:1)
为了让objectInputStream.readObject()调用您的方法,您必须将其声明为private:
private void readObject(ObjectInputStream objectInputStream)
如果你不这样做,你的方法将不会被调用(在那里设置一个断点来证明这一点)。您的代码似乎可以正常工作,但这是因为正在使用默认序列化。
您可能希望对此进行保护以允许子类化,但这不是必需的。序列化过程在调用具体类的readObject之前自动调用基类的readObject。即使具体类没有调用:
,也会发生这种情况objectInputStream.defaultReadObject();
...与我在网上看过的其他帖子相反。这同样适用于writeObject方法。