在讲座中,教授强调只有那些需要通过网络传递的类才实现Serializable接口。
这意味着让太多的类实现Serializable接口会有一些不利影响或代价。而那些不需要被发送到网络上的类则不必实现Serializable接口。
我不明白为什么会有任何不利影响,因为如果你从未将其发送到网络上,则永远不会发生序列化/反序列化。
只让需要通过网络传递的值实现Serializable接口。
您的教授建议您将使用Serializable
最小化到仅在必要的领域。
这是因为序列化很容易泄露实现细节。实现Serializable接口表明了序列化的意图(即使对象从未被序列化),这意味着开发人员在修改这些类时应该小心,以避免破坏软件。
Joshua Bloch在他的书Effective Java中详细讲解了这个问题。
当你序列化一个对象时,它被实例化的类就不能再进行修改,除非进行特殊处理†。如果你修改了这个类,那么二进制表示就不再与已序列化的对象匹配。因此,在修改类之前序列化的任何对象的反序列化都将失败。
如果一个类型实现了Serializable
接口,它就有可能被序列化。如果该类型的实例已经被序列化,那么通过修改其实现可能会破坏代码。
由于没有简单的方法可以确定可序列化类型的实例是否已经被序列化(即使你可能不打算对对象进行序列化),所以开发人员在修改这些类型的实现时要非常谨慎。
† - 这可以通过正确地对你的可序列化类型进行版本控制来避免,但由于可能会对没有契约更改的类型进行版本控制(没有编译时错误处理支持通知您),最好将显式版本控制最小化,以避免在设计中添加过多复杂性。
Serializable
接口时没有提供显式版本ID,这在我看来是必须的。你真的不想让自己处于VM实现生成版本ID的情况下。 - Sanjay T. SharmaSerializable
会增加复杂性,而且没有编译时错误处理支持(不会因为版本实现更改而得到编译器错误),因此需要特殊处理以避免出现问题。在我看来,最好将这种特殊处理与要求封装起来,缩小潜在错误的范围。 - Dioxin我认为教授所说的“只让需要通过网络进行值传递的类实现Serializable接口”有不同的理解。我的想法是,如果你必须以这种方式使用一个类,那么就要自己实现writeObject、readObject和readObjectNoData方法,这可能比默认实现更有效率。
如果不必要地实现Serializable接口会有什么惩罚?
没有因为不必要地添加implements Serializable而受到惩罚。如果您从未对对象进行序列化,则不会发生任何事情。如果您确实对其进行序列化,则它可以正常工作而不会失败。这不是一种惩罚。
为什么教授强调这一点仍然是个谜。请问他。除了在序列化时,没有额外的开销。如果您通过RMI按值传递对象,您别无选择,只能实现Serializable接口,因此没有任何东西可以评估开销。这是毫无意义的。
public class YourClass implements Serializable {
}
现在如果我写:
class MyClass extends YourClass {
private SomeoneElsesClass myField;
}
当SomeoneElsesClass
不可序列化时,我的FindBugs将使用消息“可序列化类中的非瞬态非可序列化实例字段”标记myField
。我试图使我的代码不受警告消息的影响,但在这种情况下,我无法避免。
我经常专门化Swing类。有时,我想拥有不可序列化类的实例字段,这基本上会在我的代码中引入错误。在现实生活中,我只收到一个警告消息,只要对象实际上没有被序列化,它就能正常运行;但这些警告消息仍然令我感到烦恼。
Serializable
,并且它将编译良好。 - shmosel