为什么Java需要Serializable接口?


114

我们需要大量的序列化工作,并且必须在使用的每个对象上指定Serializable标签,这是一种负担。特别是当它是第三方类时,我们无法真正更改。

问题是:由于Serializable是一个空接口,并且Java一旦添加便提供了可靠的序列化 implements Serializable-为什么它们不使所有内容都可序列化,仅此而已?

我想念什么?


如果要使自己的对象可序列化怎么办?还是我误会了什么?
乔·菲利普斯

我仍然会收到NotSerializableException,因为我对象的所有字段都必须可序列化
Yoni Roit

完全同意Pop Catalin和dmitry的观点:“这种可序列化的技巧只是十年或两年前做出的另一个错误决定”。序列化有多危险都没关系。而且,由于声明是显式的,所以“您知道您必须特别注意”是不正确的:每个需要声明的人都先放入“实现”的东西,然后再想想如果出错了。如果他们给我们提供了一个“不可序列化”的界面以用于特殊情况,那就更清楚了。
杰克

Answers:


120

序列化充满陷阱。这种形式的自动序列化支持使类内部成为公共API的一部分(这就是javadoc为您提供类持久形式的原因)。

为了实现长期持久性,类必须能够解码这种形式,这限制了您可以对类设计进行的更改。这破坏了封装。

序列化也可能导致安全问题。通过能够序列化其引用的任何对象,类可以访问它通常无法访问的数据(通过解析结果字节数据)。

还有其他问题,例如内部类的序列化形式定义不正确。

使所有类都可序列化会加剧这些问题。请查看有效的Java第二版,特别是项目74:明智地实现可序列化


2
这显然是更好的答案,我对选择的答案不是这样感到失望,似乎张贴者在选择时会想到“我因为必须声明可序列化的东西而感到恼火”。这是一个例子,有人想要放任自流,却不理会过去已经学过的安全和设计课程。
gbtimmon 2012年

@McDowell您对持久化的类表示什么意思?我跟踪了该链接,但无法理解您的意思?你能解释一下吗?
极客

@Geek - (例如)定义URL类型的序列化形式是什么私有字段的类型必须和什么样的顺序,他们必须申报。
麦克道尔

@McDowell顺序为什么重要?
极客

12
@McDowell嗨。我是4年前这个问题的原始发布者,如果有任何意义,我刚刚选择了您的答案为接受。我认为您的答案确实是更好的答案,当时我可能还不太成熟,无法以这种方式看到它。立即修复:)
Yoni Roit

32

我认为Java和.Net人士这次都错了,最好将所有内容默认设置为可序列化,而只需要标记那些不能安全地序列化的类即可。

例如,在Smalltalk(70年代创建的语言)中,每个对象默认情况下都可以序列化。考虑到绝大多数对象都可以安全地序列化,而只有少数对象不是,因此我不知道Java中为什么不是这种情况。

将对象标记为可序列化(带有接口)并不能使该对象可序列化,它一直都是可序列化的,只是现在您表达了系统可以自己发现的东西,所以我认为没有真正的理由序列化就是现在的样子。

我认为这要么是设计人员做出的错误决定,要么是事后才想到序列化,或者默认情况下该平台从未准备好安全,一致地对所有对象进行序列化。


26
在设计和实现类时,需要特别小心,以确保实例将以合理的方式序列化。可序列化的接口实际上意味着:“作为程序员,我已经了解了序列化的后果,并允许JVM对其进行序列化”
Rolf Rander 09年

@Rolf Rander:大多数时候,您根本不需要任何照顾,只需将类标记为可序列化即可。如果在所有对象上默认启用序列化功能,那么每个开发人员的想法也会有所不同,那么使类可序列化将是很自然的事情……
Pop Catalin 09年

它将在良好的类设计列表中增加另一个问题,例如确保您没有内存泄漏。尽管如此,良好的类设计越来越多地要求您的类在可以时可以序列化。
Pop Catalin 09年

3
@StaxMan,因为稍后意识到您需要序列化一个类而您不能这样做,可能会非常昂贵。这是很少付出额外努力的情况之一。如果你正在写一个图书馆和别人会消耗它没有源代码,这是尤其如此
波普克特林

2
我完全同意这个答案。在许多语言中,默认情况下所有内容都可以序列化。实际上与JVM相同,因为很容易使用反射来访问任何类成员(无论是否私有)。这一Serializable技巧只是十年或两年前做出的另一个错误决定,并且是处理纯Java时烦恼的又一个补充,例如标准库中集合和字符串处理中的一些缺陷。令人高兴的是有Kryo,但这是依赖关系,需要首先找到它。这就是应该完成内置序列化的方式。
2014年

20

并非所有内容都是真正可序列化的。以网络套接字连接为例。您可以序列化套接字对象的数据/状态,但是活动连接的本质将丢失。


这将是我的问题,如果我不够聪明,无法尝试对套接字进行序列化,则在调试期间会发现我的错误。但是,现在由于第3方类完全没有理由不实现Serializable的情况下,我根本无法使用Java序列化。
Yoni Roit

4
有几种不错的方法来处理这种情况,例如编写一个可序列化包装器类,该类知道如何读写第三方类的密钥数据。使包装的实例成为临时实例,并覆盖writeObject和readObject。
Greg Case

您可以从api中的必需对象继承并序列化这些类吗?
乔尔·科洪

@Joel:这是一个好主意,但仍然是一个技巧。我想这整件事只是另一个折衷方案。感谢您的意见。
Yoni Roit

1
这是一些罕见的例子,说明我们真正需要的是implements NotSerializable:)
罗伯·格兰特

13

默认情况下,Java中Serializable的主要作用是实际上使所有其他对象不可序列化。序列化是一种非常危险的机制,尤其是在其默认实现中。因此,就像C ++中的友谊一样,即使使事情可序列化花费一点时间,默认情况下它也处于关闭状态。

序列化增加了约束和潜在的问题,因为没有保证结构的兼容性。最好默认将其关闭。

我不得不承认,我看到过很少的非平凡类,它们在其中实现了标准序列化。特别是在复杂的数据结构的情况下。因此,您花在使类可序列化上的精力与添加接口的成本相比显得微不足道。


9

对于某些类,尤其是那些表示更物理类的类,例如文件,套接字,线程或数据库连接,序列化实例绝对没有任何意义。对于许多其他人,序列化可能会带来问题,因为序列化会破坏唯一性约束,或者只是迫使您处理类的不同版本的实例,而您可能不想这样做。

可以说,最好将所有内容默认设置为可序列化,并通过关键字或标记接口将类设置为不可序列化-但是,那些应该使用该选项的人可能不会考虑。这样的话,如果您需要实现Serializable,则会通过Exception告知您。


4

我认为尽管如此是为了确保您作为程序员知道您的对象可以序列化。



1

必须明确声明某个类的实例是可序列化的,因此该语言迫使您考虑是否应该允许这样做。对于简单的值对象,序列化是微不足道的,但是在更复杂的情况下,您需要认真考虑。

仅依靠JVM的标准序列化支持,您就可以面对各种讨厌的版本控制问题。

唯一性,对“真实”资源的引用,计时器和许多其他类型的工件都不适合序列化。



0

好吧,我的回答是,这没有充分的理由。从您的评论中,我可以看到您已经了解了这一点。其他语言愉快地尝试对数到10之后没有跳到树上的所有内容进行序列化。对象应默认可序列化。

因此,您基本上需要做的是自己阅读3rd-party类的所有属性。或者,如果这是您的选择,请执行以下操作:反编译,将该死的关键字放在此处,然后重新编译。


2
序列化增加了约束和潜在的问题,因为没有保证结构的兼容性。恕我直言,最好默认将其关闭。
Uri 2009年

我不确定您所说的“结构兼容性”是什么。
nes1983

0

Java中有些东西根本无法序列化,因为它们是运行时特定的。流,线程,运行时等内容,甚至某些GUI类(连接到底层OS)都无法序列化。


0

尽管我同意此处其他答案的观点,但真正的问题在于反序列化:如果类定义发生更改,则存在真正的风险,即反序列化将无法进行。对于图书馆作者来说,绝不修改现有字段是一项重大的承诺!保持API兼容性就足够了。


这是不正确的。您需要阅读“ 对象序列化规范” 的“可序列化对象版本控制”一章,如果您在此声明是正确的,那么该章节将不存在。在与先前的序列化不兼容之前,类定义可以在相当大的范围内更改。这当然不是问题的答案。真正的原因与安全问题有关。
2013年

@EJP,为了真实起见,我编辑了答案以反映您的观点。不过,这种情绪
依然存在

0

需要持久化到文件或其他媒体上的类必须实现Serializable接口,以便JVM可以允许对类对象进行序列化。为什么不对Object类进行序列化,那么所有类都无需实现接口,毕竟只有当我使用ObjectOutputStream时,所有JVM才会对类进行序列化,这意味着控件仍在我手中,可以让JVM对序列化。

对象类默认情况下无法序列化的原因是该类版本是主要问题。因此,每个对序列化感兴趣的类都必须显式标记为Serializable并提供版本号serialVersionUID。

如果未提供serialVersionUID,则在反序列化对象时会得到意外结果,这就是为什么如果serialVersionUID 不匹配,JVM会抛出InvalidClassException的原因。因此,每个类都必须实现Serializable接口,并提供serialVersionUID以确保两端显示的类相同。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.