2009-10-05 42 views
3

我有以下问题:匿名类的二进制名

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表示匿名类的名称应该是封闭类的名称,“$” - 不对这些序列设置任何约束的符号和非空序列。

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

回答

1

我可以猜出为什么它失败的唯一原因是新的Java版本重新排列类名,因为您在_1中引用_2。也就是说,我不认为你可以依赖这些名字,因为Java并没有确定它将按照何种顺序处理一个类的字段(因此,它将创建内部类的顺序)。

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

+0

在A $ 1类的反序列化过程中,出现“本地类不兼容”异常。发生这种情况是因为名称A $ 1的类定义与序列化期间的类定义不同。 – okutane

+0

在这种情况下,[本文] [http://www.informit.com/articles/article.aspx?p=31936]可能会有所帮助。 –

+0

是的,这是编译器的差异。然而,我还没有想出它...... – okutane

4

我敢挑战一些元素吗?希望这能对你有用:

  1. 如果你希望你的类有一个著名的名字......嗯,匿名是一个名为类的相反! ;-)
  2. preserializing和交付对象作为二进制数据是一个危险的选择,你被它咬了(在重构过程中,但我相信这可能发生在许多其他条件)。序列化数据通常被认为是Java中的短期解决方案,可以持续几秒钟。许多其他选项可用于长期存储。现在

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

+0

我不关注你对后向引用的评论吗?你的意思是静态初始化命令的问题? /非瞬时序列化可以完成,但是如果你对它进行一些预先考虑,它会变得更容易。 –

+0

@Tom是的,向后引用避免了静态初始化的一些问题。但是,**的东西附加在您阅读它们的顺序**中,当您试图获得精确的订单时,这非常重要:-) – KLE

1

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

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