能否使用指定Comparator反序列化SortedSet、TreeSet、SortedMap或TreeMap?
当然可以实现,但这里有几个容易踩坑的细节得给你说清楚:
首先确保你的Comparator是可序列化的
TreeSet和TreeMap在序列化时,会把它们依赖的Comparator对象一并写入序列化流中。如果你的自定义Comparator没有实现Serializable接口,反序列化时直接会抛出NotSerializableException,这是最常见的错误。举个例子:// 错误示范:未实现Serializable,反序列化会失败 class DescendingComparator implements Comparator<Integer> { @Override public int compare(Integer o1, Integer o2) { return o2.compareTo(o1); } } // 正确示范:实现Serializable接口 class SerializableDescendingComparator implements Comparator<Integer>, Serializable { @Override public int compare(Integer o1, Integer o2) { return o2.compareTo(o1); } }反序列化会自动沿用原Comparator的排序逻辑
当你序列化一个用自定义Comparator创建的TreeSet/TreeMap时,反序列化出来的实例会自动使用原来的Comparator——因为这个Comparator已经被序列化到流里了。不需要你额外指定,JVM会帮你还原整个对象的状态,包括排序规则。如果你想在反序列化后改用其他Comparator重新排序,那只能重新创建一个新的TreeSet/TreeMap实例,传入新的Comparator,再把反序列化得到的元素全部加进去,比如:
// 假设已经反序列化得到了deserializedSet TreeSet<Integer> newSetWithNewComparator = new TreeSet<>(new AscendingComparator()); newSetWithNewComparator.addAll(deserializedSet);SortedSet/SortedMap接口的反序列化规则
SortedSet是接口,实际序列化/反序列化的都是它的实现类(比如TreeSet);同理SortedMap对应的实现是TreeMap。所以它们的反序列化规则和TreeSet/TreeMap完全一致,不需要额外处理。特殊情况:自然排序的场景
如果你的TreeSet/TreeMap用的是自然排序(也就是元素实现了Comparable接口,创建时没有指定Comparator),反序列化也完全没问题——此时Comparator字段为null,反序列化后集合会自动回到自然排序的逻辑,只要元素本身是可序列化的就行。额外提醒:Comparator的状态要能正确还原
如果你的Comparator依赖了某些外部状态(比如一个配置参数),那这些状态也必须是可序列化的,或者在反序列化后能正确初始化。否则反序列化后的Comparator可能会出现逻辑异常,导致集合排序不符合预期。
内容的提问来源于stack exchange,提问作者Jan-Willem Gmelig Meyling

