匿名类二进制名称

时间:2009-10-05 12:59:51

标签: java

我有以下问题:

1)有一些抽象类A,其中有几个匿名子类存储在A的静态字段中。两个匿名子类之间存在循环依赖关系。该抽象类的代码类似于以下内容:

class A implements Serializable
{ 
    public static final A _1 = new A() {
        public A foo()
        {
            return _2;
        }
    };

    public static final A _2 = new A() {
        public A foo()
        {
            return _1;
        }
    };

    public static final A _3 = new A() {
        public void bar()
        {
            // do something
        }
    };
}

2)类A的实例由序列化中使用的其他对象引用。有些对象由开发人员预先序列化,然后作为二进制数据包含在发布中。

在A类的一些重构之后,在发布版本中更改了匿名子类的二进制名称。我想这可能是由于java编译器版本的不同。从我的机器上生成的.class文件中我可以看到存储在_1,_2和_3字段中的A的匿名子类分别具有名称A $ 1,A $ 2和A $ 3,但是从发布版本中获取的.class文件我可以看到存储在_1,_2和_3字段中的A的匿名子类分别具有名称A $ 2,A $ 3和A $ 1。由于这种预先序列化的数据变得无法使用,我需要以某种方式解决这个问题。

java编译器或JVM是否有任何规范可以说明我的匿名类应该具有哪些二进制名称? JLS表示匿名类的名称应该是封闭类的名称,“$” - 符号和非空数字序列,而不对这些序列设置任何约束。

我相信我不应该依赖匿名类的内部名称,我也知道“正确”的方法来解决这个问题,比如在构建服务器上生成预序列化数据。太糟糕了,我们现在没有太多时间,所以我想知道这个命名差异来自哪里,所以我现在可以解决这个问题。

3 个答案:

答案 0 :(得分:4)

我敢挑战一些元素吗?希望它对您有用:

  1. 如果你希望你的课程有一个众所周知的名字......好吧,匿名与命名的类相反! ; - )
  2. 对象预先序列化并作为二进制数据传递是一个危险的选择,并且你被它咬了(在重构期间,但我相信在许多其他条件下可能会发生这种情况)。序列化数据通常被认为是Java中的短期解决方案,可以持续几秒钟。许多其他选项可用于长期存储。

  3. 现在,如果要求解决您的短期问题,我看到的唯一方法是将您的类恢复到与先前版本兼容的状态。如果您提到的不同顺序是唯一的区别,我相信以与以前相同的顺序定义匿名类值得尝试!还要注意引用应该向后(对于文件中较早的类),而不是向前(对于文件中稍后的类)。

答案 1 :(得分:1)

我可以猜到它失败的唯一原因是新的Java版本重新排序了类名,因为你引用了_2中的_1。也就是说,我不认为你可以依赖这些名称,因为Java不保证它将处理类的字段的顺序(因此,它将创建内部类的顺序)。

但我认为你的问题在其他地方。你得到什么错误?

答案 2 :(得分:1)

你的编译器没有发出任何警告吗?

我相信您可以通过覆盖ObjectInputStream.readClassDescriptor来阅读数据,而无需依赖当前代码中的匿名类名。替换为“兼容”类的描述符。没有保证可行,但如果您的数据很重要,可能值得一试。