1

先说问题,故事如下:

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

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

  • Class A 编译为 Java 1.6 字节码,并具有泛型等 1.6 特性。继承者 B 和 C 被编译为 1.4 字节码。
  • 接口我编译为1.6,而实现器编译为1.4。
  • 其他涉及不同版本字节码的奇异继承场景。

我已经尝试了我能想象到的许多场景,它似乎运行得很好。但是我仍然有想在这里提问的冲动,因为我只了解表面上的 Java;我知道如何编写和调整 Java,但并不真正知道幕后发生了什么。

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

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

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

4

5 回答 5

3

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

保持目标版本明确还意味着您可以升级您的 SDK,而不必担心您的 JAR 文件对旧版 JVM 不可用。

于 2012-04-19T08:56:24.867 回答
3

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

字节码的工作方式几乎没有变化

  • JVM 不支持嵌套类访问外部类的私有成员,这通过生成的代码来工作。
  • JVM 不支持对泛型的运行时检查,例如,您不能new T()在 T 是泛型的情况下进行检查。

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

于 2012-04-19T09:01:56.937 回答
2

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

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

找出答案的最佳方法是在小规模上进行概念验证类型的项目。

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

于 2012-04-19T09:09:46.187 回答
1

只要您不使用反射,不同字节码版本可能遇到的唯一主要问题就是ACC_SUPER标志。

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

然而,这是古老的历史。在 1.4 和更高版本中编译的每个类都会有标志,所以这不是问题。字节码方面,1.4 和 1.6 之间唯一的主要区别是添加了可选属性,用于存储有关内部类、泛型、注释等的元数据。

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

于 2013-04-06T03:04:48.723 回答
1

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

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

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

于 2012-04-19T09:25:55.757 回答