FindBugs希望readObject(..)在序列化时是私有的,为什么?



我在一些代码上运行findbugs,它说readObject(…)方法必须是私有的才能调用序列化/反序列化?为什么?如果公开会有什么问题?

关于readObject()/writeObject()是私有的,情况是这样的:如果你的类Bar扩展了一些类Foo;Foo也实现了readObject()/writeObject(), Bar也实现了readObject()/writeObject()

现在,当Bar对象被序列化或反序列化时,JVM需要自动为Foo和Bar调用readObject()/writeObject()(即不需要显式调用这些超类方法)。然而,如果这些方法不是私有的,它就变成了方法覆盖,JVM就不能再在子类对象上调用超类方法。

因此它们必须是私有的!

在现代Java实现中(至少JDK 6到10),ObjectInputStreamObjectOutputStream类将只识别readObject, readObjectNoDatawriteObject方法,如果它们被声明为private而不是static

(我在任何文档中都找不到明确的说明,但代码中明确实现了该限制。)

所以,不管这是不是一个好主意,FindBugs指出非私有readObject方法是一个错误是正确的。它不会被使用。

我想把这个方法设为public的唯一原因是把它设为final,这样继承的对象就不能篡改它了。

我认为你不应该尝试那样做。在类级别的javadoc中注明您认为子类应该做什么和不应该做什么。如果有人选择实现一个类而忽略了这个建议,那么处理后果是他们的问题。

试图强迫其他人以特定方式实现子类的问题是,他们可能有一个用例,要求他们做不同的事情…因为你无法理解的原因。让未来的开发人员自由地做他们想做的事情,并让他们对结果负责,这是一个更好的主意。

我不确定为什么findbugs认为这是一个bug,但我可以猜测两个可能的原因。将readObject设为公共会破坏封装,因为调用代码可以看到类的内部结构。此外,通过将其设为公共,可以强制所有派生类将readObject声明为公共。所以除非这个类是final的,否则你是在改变序列化的契约。

我认为findbugs可以为它的大多数消息提供基本原理。这上面有什么要说的吗?

您没有理由自己调用诸如readObject之类的序列化方法,更不用说从另一个类调用了。你应该尽可能地减少可见性。

编辑:如果你想子类能够改变行为,使方法protected…这是可以接受的。

为了让你的方法被objectInputStream.readObject()调用,你必须将它声明为private:

private void readObject(ObjectInputStream objectInputStream)

如果你不这样做,你的方法将不会被调用(在那里放置一个断点来证明这一点)。您的代码可能看起来可以工作,但那是因为正在使用默认的序列化。

您可能想要使此保护以允许子类化,但这不是必需的。序列化进程在调用具体类的readObject之前自动调用基类的readObject。即使具体类没有调用:

,也会发生这种情况。
objectInputStream.defaultReadObject();

…与我在网上看到的其他帖子相反。这同样适用于writeObject方法

相关内容

最新更新