在类层次结构中混合使用Java 1.4和1.6字节码

问题首先,故事将遵循:

在类层次结构中混合使用不同的字节码版本是否安全? 有什么风险?

对于一个案例,C类扩展B,B类扩展A类.A类实现接口I.我的问题将涉及以下示例场景:

  • A类编译为Java 1.6字节码,并具有1.6特性,如generics等。inheritance人,即B和C被编译为1.4字节码。
  • 接口我编译为1.6,而实现者编译为1.4。
  • 其他奇异的inheritance场景涉及不同版本的字节码。

我尝试了很多我能想象到的场景,似乎运行得很好。 但是我仍然觉得这里要求的冲动,因为我只知道表面上的Java; 我知道如何编写和调整Java,但不知道在幕后发生了什么。

现在对于那些无法自拔的人来说,“为什么你需要这样做?”。

我正在一个项目中评估通过RMI连接到EJB 2的旧Java 1.4 Swing应用程序到连接到运行在1.6之上的新版App Server的Java 1.6 Swing的迁移。 J2EE平台仍然是1.4(EJB 2)。

迁移不会“重新编译所有内容到1.6”,但它将是“代码并将新function编译为1.6”。 他们做事的方式是这样的:他们在CVS中只有一条路径,每个人都在那里提交。 没有任何标签/分支来获取生产代码。 每当需要添加新function时,他们从生产服务器获取JAR,爆炸它们,根据需要替换或添加新类,重新打包jar子,将它们放回服务器。 因此,如果他们将使用Java 6编译并使用上述方法进行部署,那么将会有很多exception混合的1.4和1.6字节码。

Java 1.0和Java 6之间的JVM字节代码没有显着差异。在Java 7中,它们添加了一条新指令。 哇噢。

字节码的工作方式变化很小

  • JVM不支持访问外部类的私有成员的嵌套类,这通过生成的代码来工作。
  • JVM不支持对generics的运行时检查,例如,您不能使用new T() ,其中T是generics。

基本上,它们使JVM变得更加智能和快速,但直到最近才不惜一切代价改变了字节代码工作方式的模型。

您可以使用Java 6进行编译,但使用编译器设置进行目标1.4。 我们曾为迁移项目做过一次。 如果/当1.4消失,则再次更改编译器设置并以1.6为目标。

保持目标版本显式也意味着您可以升级SDK而不必担心JAR文件对旧JVM无法使用。

我正在使用Sun JVM 1.5在Tomcat上维护一个包含1.4(旧库jar)和1.5(我的修复和东西)类的环境,它运行正常。

但是,对于RMI,如果客户端和服务器具有不同的类版本,则可能会遇到麻烦,因为服务器可能会检查类版本(我遇到了这个问题)。

找出的最佳方法是小规模地进行项目概念validation。

一个友好的提醒,你在这里为自己挖一个很大的洞:-)

这些链接似乎相关。 他们记录了几个可能破坏1.4和1.5 之间以及1.5和1.6之间兼容性的边缘情况。

可能导致我能想到的问题的最大差异是enum成为关键字,但是在加载旧的类文件时这只会影响1.5+ JVM(这似乎不是你将要做的)。 另一件事是注释。 上面的链接似乎表明一切都会好的,但我会担心如果旧的JVM加载了一个带有运行时注释的类会发生什么。

除此之外,我认为第一版java和java 6之间没有任何字节码更改。这意味着您应该遇到的唯一问题是API或弃用function的更改(在上面的链接中列出)。

只要您不使用reflection,您可以从不同的字节码版本中获得的唯一主要问题是ACC_SUPER标志。

在早期版本中,未正确处理超类方法的调用。 当他们修复它时,他们为类文件格式ACC_SUPER添加了一个新标志来启用它,以便依赖于旧的,破坏的行为的应用程序不受影响。 当然,使用不包含此标志的类可能会导致问题。

然而,这是古老的历史。 在1.4及更高版本中编译的每个类都将具有该标志,因此这不是问题。 字节顺序,1.4和1.6之间的唯一主要区别是添加了用于存储有关内部类,generics,注释等的元数据的可选属性。

但是,这些不会直接影响字节码执行。 这些影响的唯一方法是通过reflection访问它们。 例如, java.lang.Class.getDeclaredClasses()将从可选属性InnerClasses返回信息。