5

在有效的 Java 书籍的第 74 项中有一段(第 74 项最后的第 2 段),其中提到如下:

内部类(Item 22)不应该实现 Serializable。他们使用编译器生成的合成字段来存储对封闭实例的引用并存储封闭范围内的局部变量的值。这些字段如何对应于类定义是未指定的,匿名类和本地类的名​​称也是如此。 因此,内部类的默认序列化形式定义不明确。

我知道内部类使用编译器生成的合成字段来存储对封闭实例的引用,例如,如果封闭类是 MyEnclosure 并且内部类是 MyInner,那么封闭引用是 MyEnclosure.this。但我无法获得BOLD部分。请帮我理解意思。谢谢!!!

4

3 回答 3

6

假设你有一个像这样的本地类:

 class OuterClass {
    Runnable run;

    void method() {
       final int a = 8;
       this.run = new Runnable() {
          public void run() {
             System.out.println(a);
          }
       };
    }
 }

现在假设我尝试序列化this,其中包含此内部类类型的对象。我的编译器命名该类OuterClass$1并给它一个名为val$a. 但是在这种情况下使用的确切名称不是编译器规范的一部分。另一个编译器可能会选择调用内部类OuterClass$method$1。在这种情况下,即使使用相同的源文件,在一个编译版本中序列化并在另一个版本中反序列化都会失败。

(另外,还有匿名内部类没有无参数构造函数的问题。但是由于上面的问题,即使是命名的内部类也不能可靠地序列化)

于 2013-03-21T20:58:01.370 回答
1

考虑以下代码:

public class Main {
    public static void main(String[] args) {
        final int x = Integer.valueOf(args[0]);
        new Object() {
            void print() {
                System.out.println(x);
            }
        }.print();
    }
}

我的编译器调用匿名内部类Main$1。当我反汇编它时,我看到x外部范围的值的副本存储在一个名为的私有字段中val$x

private final int val$x;

这是粗体部分所说的一个例子。

于 2013-03-21T21:02:27.977 回答
0

内部类是在其他类中定义的非静态类:

class Outer implements Serializable {
    private String someString;

    class Inner implements Serializable {
        private int someInt;
    }

}

一旦你有一个Inner类的实例,当你序列化它时,它必须有一个对外部类的引用(它通过Outer.this引用在内部访问它),并且未指定如何为序列化对象实现这一点。这同样适用于本地类:

class Outer implements Serializable {
    private String someString;

    Serializable method(final int i) {
        class Inner implements Serializable {
            Inner() {
                System.out.println(i);
            }
        }
        return new Inner();
    }
}

如果你序列化返回的值method(),它需要有一个对 的引用i,但这并不可靠。

于 2013-03-22T02:56:05.757 回答