Java:如何确保可序列化集合

20
在Java中,Collection接口之所以没有扩展Serializable接口,是由于一些充分的原因。另外,这些接口的大多数常见实现都实现了Serializable接口。
因此,如果实现本身是可序列化的(通常情况下是这样的),并且集合中的对象都是可序列化的,则实现了其中一个Collection接口的对象就可以被序列化。
但是我该如何确保这两个条件得到满足呢?我不想遇到运行时错误,因为编译器可以检查这些条件。我在考虑是否可以添加类似于以下例子中List接口的显式接口:
public interface SerializableList<T extends Serializable> extends Serializable, List<T> {}

我想知道是否还有其他人遇到过这个问题并想出了这个简单的解决方案。到目前为止,我还没有找到任何解决方案或讨论,这让我对我的想法产生了怀疑。


如果我理解你的问题正确,你可以将你的List引用定义为List<T extends Serializable>。你不需要自己编写接口。 - Rohit Jain
2
@RohitJain:你的提议只保证列表中的对象是可序列化的,但并不保证列表实现本身是可序列化的。 - MrD
@JBNizet:当然,SerializableList的具体实现除了保存添加的对象的对象数组之外,可能还包含一些不可序列化的属性。但在这种情况下,我会说这是实现中的一个错误。 另一方面,如果只有可序列化的对象可以添加到列表中,则保存对象的属性(例如数组)也应该是可序列化的。 - MrD
1
你没有抓住我的重点。即使是 ArrayList<Serializable> 也不能被序列化。ArrayList 是可序列化的,它只包含 Serializable 的实例。但是,一旦这些包含对象中的任何一个包含了非序列化字段,它就不再是可序列化的。无论你添加多少个通配符限制,你都可能在运行时遇到错误。因此,请使用测试。 - JB Nizet
1
是的。当你想要序列化时,使用不可序列化的集合也是一个bug。通过编写测试来捕获错误。 - JB Nizet
显示剩余2条评论
3个回答

11
你所需求的实际上是将两种类型合并成一种类型定义: <type-def> a = null; 你需要用一个规范替换<type-def>,确保a引用的对象既实现了Serializable,又实现了Collection<? extends Serializable>。然而,Java语言本身并不支持这样的类型定义。
正如你已经提到的,最明显的解决方案可能是声明一个新接口,将这两个接口合并在一起: interface SerializableCollection<T extends Serializable> extends Collection<T>, Serializable {} 看起来没问题,直到你尝试像这样做: SerializableCollection<String> a = new ArrayList<String>(); 然而,这段代码无法编译通过。即使ArrayList<String>实现了Collection<? extends Serializable>Serializable,但它并没有实现SerializableCollection<String>
现在,你可以声明一个新类来绕过这个问题: SerializableArrayList<T extends Serializable> extends ArrayList<T> implements SerializableCollection<T> {} 现在,你已经将所有需要的东西组合在一起,可以满足原始需求: SerializableCollection<String> a = new SerializableArrayList<String>(); 这样做值得吗?在你的情况下,你必须自己决定,但我认为不值得。我的理由是,由于Serializable标记只是一个非正式的“标签”,确保你的集合和其内容都实现了Serializable仍然不能保证集合和其内容实际上可以被序列化。

1
谢谢。我现在觉得一切都很清楚了。正如你和JB Nizet所说,我不能依赖实现Serializable接口的对象真的是可序列化的(这很遗憾)。我认为这就是关键:值得这样做吗?如果适用于我的情况,我会考虑一下。 - MrD

7

Serializable并不是一个很好的接口。如果在它被实现时注解可用,它应该是一个注解。

如果你需要处理的是一个不可序列化的东西的List列表,你需要确保对象图中没有任何对象是不可序列化的,否则会出错。并非所有实现Serializable的对象都可以被序列化。


那么没有办法在编译时检查吗? - Narendra Pathai
interface SerializableCollection<T extends Collection<? extends Serializable>>{} 可以做到这样吗? - Narendra Pathai
1
一个由不可序列化的对象组成的List不能被添加到SerializableList中,因为这个List没有实现Serializable接口。当然,我可以添加一个包含一些不可序列化对象的ArrayList(它是可序列化的) - 但只有在我将其用作原始类型时才能这样做。如果它被参数化,编译器应该会抱怨这一点。 - MrD
1
好的,我现在明白了。使用ArrayList可以添加非可序列化对象,这会导致运行时错误。请参见问题中的注释。 - MrD

1
一种克隆集合及其包含对象的方法是:
import org.apache.commons.lang3.SerializationUtils;
...
ClonedArrayList = SerializationUtils.deserialize(SerializationUtils.serialize(OriginalArrayList))

例如,通过使用ArrayList<Type>(collection)(因为SerializationUtils需要Serializable接口)来实现。

祝好, Gunnar


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接