序列化中参考共享的含义是什么?枚举如何序列化?

时间:2013-08-02 09:44:47

标签: java

我正在阅读ObjectOutputStream Documentation并阅读有关序列化的内容,我有一些困惑。它说明了

  

使用引用对单个对象的多个引用进行编码   共享机制,使对象的图形可以恢复到   与写原稿时的形状相同。

refence共享机制的含义是什么?它还说明了

  

枚举常量的序列化与普通的可序列化不同   或可外部化的对象。枚举常量的序列化形式   仅由其名称组成;常量的字段值不是   传输。要序列化枚举常量,ObjectOutputStream会写入   常量名称methodLike其他返回的字符串   可序列化或可外化的对象,枚举常量可以作为   随后出现在后面的参考目标   序列化流。

我能想到的一个原因是,因为Enum字段是常量,所以它们不会被序列化。 那么我们是否需要序列化枚举呢?另一件事,如果国家不能 为了序列化,为什么编译器不限制我们序列化枚举?是什么 这意味着,枚举常量可以作为反向引用的目标吗?

请帮助澄清这个疑问。感谢。

3 个答案:

答案 0 :(得分:3)

  

使用引用对单个对象的多个引用进行编码   共享机制,使对象的图形可以恢复到   与写原稿时的形状相同。

这意味着可以序列化包含循环的对象图。

换句话说,如果要序列化以下图表:

A - > B - > C - > A(C指回A)。

如果序列化A,它将执行以下操作:

  1. 序列化A
  2. 走A的对象树,找到B
  3. 序列化B
  4. 的简单字段
  5. 走B的对象树,找到C
  6. 序列化C
  7. 的简单字段
  8. 走C的对象树,找到A
  9. 指针发送到流中的A
  10. 如果没有这样做,那么序列化A将导致无限循环。

      

    枚举常量的序列化与普通的可序列化不同   或可外部化的对象。枚举常量的序列化形式   仅由其名称组成;常量的字段值不是   传输。要序列化枚举常量,ObjectOutputStream会写入   常量名称方法返回的字符串

    因为枚举是常量,所以假设它们在使用它们的地方总是具有相同的状态,因此不必向下发送枚举的状态。因此,当接收方接收并枚举时,它只是查找该枚举的对象,并将其作为枚举返回,即使任何一方的两个枚举可能具有不同的状态。

答案 1 :(得分:1)

使用参考共享机制对单个对象的多个引用进行编码意味着:

如果您有一个对象图,那么该图中的每个对象仅被序列化一次,而不管该图中对它的引用数量。例如,如果在这样的图形中有对象A,B,C和D:

enter image description here

虽然可以通过路径A - >到达对象D. B - > D和A - > C - > D对象序列化机制足够智能,可以识别它在通过第二条路径到达它时已经序列化了对象D,因此不会尝试再次序列化它。我怀疑(虽然从来没有仔细研究过),对象图在参考术语中被序列化,并且每个对象都只有它的主要和存储参考。这不仅对最小化序列化对象图的大小很重要,而且对处理循环引用也很重要。

枚举常量的序列化方式与普通的可序列化或可外部化的对象不同,因为正如您所说,Enum旨在成为常量。虽然可以解决这个问题,但是当在另一个JVM中取消激活时,在一个JVM中序列化的枚举会出现不同,这可能是将运行时状态添加到枚举中的结果。

答案 2 :(得分:0)

第一个问题:这意味着明显的事情。如果对象出现多次,它将被序列化一次。即:

Something s1 = new Something(), s2 = new Something();
List<Object> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s2);
list.add(list);

将序列化两个对象,在数组列表的两个插槽中共享对s2对象的引用。即使你有循环依赖(list包含对它自己的引用),它也会被正确处理 - 对象图按原样传输。

枚举序列化意味着另一个显而易见的事情。它使用枚举名称进行序列化和反序列化。如果您序列化某些内容,通过线路发送它,并使用不同版本的枚举类反序列化,则会执行此操作。例如。从序列化枚举a时:

class MyEnum {a,b,c}

然后在另一个具有这样的枚举的JVM中反序列化:

class MyEnum {aa, a, bb, c, d}

尽管枚举的位置(序数)已更改,但您可能会获得相同的a值,并且可能还有其他一些功能(如哈希码的值)。