【问题标题】:Java Serialization Problems, while using guava Lists.transformJava 序列化问题,同时使用 guava Lists.transform
【发布时间】:2012-02-23 17:27:53
【问题描述】:

我必须序列化一个复杂对象,但它的一个组件是不可序列化的(第三方图形对象),所以我创建了这个 Graph 类的自定义可序列化版本并使用 Guava List 转换来转换不可序列化反对自定义对象。序列化 writeObject 仍然失败。我会很想知道为什么?我的假设是 Lists.transform 懒惰地执行其操作(持有对原始对象的隐藏引用。)

还有解决这个问题的方法吗?

【问题讨论】:

    标签: java serialization guava


    【解决方案1】:

    Lists.transform() 确实像您所怀疑的那样懒惰地执行。你可以做一个

    Lists.newArrayList(Lists.transform(...))
    

    或者,如果你想要一个不可变的版本,

    ImmutableList.copyOf(Lists.transform(...))
    

    然后序列化结果列表。

    【讨论】:

    • 您不必创建新列表,请参阅@eneveu 答案。
    • OP 声明 fromList 特别充满了不可序列化的元素。
    • @Xaerness 你能修改你的评论吗?仅使用枚举技巧(@eneveu 答案)无法获得可序列化的列表。这个答案对这个问题最有用。
    【解决方案2】:

    Lists.transform() 返回原始列表的转换视图。来自 Lists.transform() javadoc:

    返回的列表总是实现Serializable,但是序列化 只有当 fromList 和 function 可序列化时才会成功。

    序列化转换后的视图时,实际上是在序列化原始列表以及函数。在您的情况下,它失败了,因为您的原始列表不可序列化(因为它包含不可序列化的图形元素)。但它也可能会失败,因为该函数没有实现可序列化。

    顺便说一句,有一个小技巧可以创建没有冗长的可序列化函数。而不是这样做:

      private static final class MyFunction extends Function<String, String> implements Serializable {
        private static final MyFunction INSTANCE = new MyFunction();
    
        @Override
        public String apply(String input) {
          return "[" + input + "]";
        }
    
        private Object readResolve() {
          return INSTANCE;
        }
        private static final long serialVersionUID = 1;
      }
    

    您可以使用枚举单例模式,它不那么冗长,并且可以免费进行序列化(因为枚举是可序列化的)。它还确保您的 Function 是单例:

      // enum singleton pattern
      private enum MyFunction implements Function<String, String> {
        INSTANCE;
    
        @Override
        public String apply(String input) {
          return "[" + input + "]";
        }
      }
    

    【讨论】:

    • 真棒...有效的Java。谢谢。
    • 是的,Joshua Bloch 在 Effective Java 中解释说,这是创建单例的最佳方式。枚举是可序列化的,不易受到各种反序列化攻击,JVM 保证其唯一性。您可以在 Guava 库中找到很好的模式示例:code.google.com/p/guava-libraries/source/browse/guava/src/com/…
    • 引用 EJ 和在 Guava 中应用良好模式的奖励积分,即使答案不是那么有用,因为 fromList 不会被序列化。
    【解决方案3】:

    如果您尝试序列化从 Lists#transform 返回的列表,则接口 List 本身是不可可序列化的。

    【讨论】:

    • 为什么会有问题?这是在序列化过程中考虑的实现。而Lists.transform()返回的实现确实实现了Serializable:“返回的列表总是实现Serializable,但是只有fromList和function都可以序列化时,序列化才会成功。” (来自javadoc
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-25
    • 2014-09-09
    • 2012-01-19
    • 2014-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多