【问题标题】:Why is a serializable inner class not serializable?为什么可序列化的内部类不可序列化?
【发布时间】:2011-10-31 23:24:19
【问题描述】:

以下代码:

public class TestInnerClass {

    public static void main(String[] args) throws IOException {
        new TestInnerClass().serializeInnerClass();
    }

    private void serializeInnerClass() throws IOException {
        File file = new File("test");
        InnerClass inner = new InnerClass();
        new ObjectOutputStream(new FileOutputStream(file)).writeObject(inner);
    }

    private class InnerClass implements Serializable {

        private static final long serialVersionUID = 1L;

    }

}

抛出以下异常:

Exception in thread "main" java.io.NotSerializableException: TestInnerClass

我猜内部类有一个TestInnerClass.this 字段,允许它私有访问TestInnerClass 的字段和方法。声明内部类为静态solves it,但如果InnerClass 需要此访问权限怎么办?有没有办法在没有封闭类的情况下序列化非静态内部类,例如通过引用外部类transient?

edit:例如,只有在序列化之前才需要访问外部类。好的,编译器不知道,但我认为这就是 transient 关键字存在的原因。

【问题讨论】:

  • 您是否尝试将内部类声明为静态? private static class InnerClass

标签: java serialization inner-classes


【解决方案1】:

如果 InnerClass 需要这种访问权限怎么办?

那么它需要外部类实例,并且必须与内部类一起序列化。

有没有办法在没有封闭类的情况下序列化非静态内部类,例如通过引用外部类瞬态?

没有。当你反序列化这样一个类然后尝试调用外部类的实例方法时会发生什么? NullPointerException?

【讨论】:

  • 在我的情况下,内部类在实际序列化之前需要访问(而不是在反序列化之后)。之后它只用作不知道外部类的超类。
  • @tb189:您始终可以通过将字段transient TestInnerClass parentClass 添加到InnerClass 来打破非静态依赖关系,并在反序列化时处理它。
  • 这确实是一种处理方法,类似于对TestInnerClass.this 的临时引用。
  • @dma_k outerClass,你的意思是。外部!=父母。虽然你是对的,它是解决方案。
  • @Boann:在上面的例子中,InnerClass 是内部类,TestInnerClass 是外部类。如果给定的内部类是嵌套类,则不会引发异常,因为嵌套类没有对其容器类的隐式引用。有关术语,请参阅this post
【解决方案2】:

让 TestInnerClass 可序列化怎么样?

public class TestInnerClass implements Serializable { }

【讨论】:

  • 这是可能的,但并不总是需要,因为这会为序列化类添加大量数据。
  • @EJP:总有更可取的解决方案(分离需要访问的内部类部分,然后使用瞬态字段 TestInnerClass 将其转发给静态可序列化类,维护另一个可序列化内部类中的对象)。它还意味着在外部类瞬态中声明所有字段,这似乎是一个设计缺陷。不是因为目前的情况不起作用,所以应该立即使用第一个替代方案/hack。
【解决方案3】:

InnerClass 不能被序列化,因为要实例化它(根据反序列化期间的要求),您需要引用外部类的实例

如果没有外部类的实例,内部类的实例就无法存在。

OuterClass o = new OuterClass();
OuterClass.InnerClass o_i = o.new InnerClass();

如果使用静态内部类,则可以序列化静态内部类。静态内部类的实例可以独立创建。

OuterClass o = new OuterClass();
OuterClass.InnerClass i = new OuterClass.InnerClass();

【讨论】:

  • 也许做一个 Github gist 或一个完整的可重复的例子会很好,你不觉得吗?
猜你喜欢
  • 2014-10-24
  • 2010-12-27
  • 2011-05-03
  • 2013-08-05
  • 2013-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-01
相关资源
最近更新 更多