【问题标题】:Mixing Java 1.4 and 1.6 bytecode in a class hierarchy在类层次结构中混合 Java 1.4 和 1.6 字节码
【发布时间】:2012-04-19 08:51:17
【问题描述】:

先有问题,接下来是故事:

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

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

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

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

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

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

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

【问题讨论】:

  • 您在上一段中解释的开发过程听起来像是这里的真正问题。您也许能够使 1.4/1.6 混合工作,但在这个过程中,您将在神器地狱中结束。
  • 听起来您的公司(至少)未能通过the Joel Test 的第 2 项和第 3 项。
  • 我们是独立软件开发商,在这里交了一个银行的项目。该应用程序最初是在内部开发的。不过你是对的,银行(不是我们公司 :) 在 Joel 测试中没有通过这些分数。

标签: java bytecode


【解决方案1】:

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

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

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

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

【讨论】:

  • 我将“直到最近不惜一切代价避免改变字节码工作方式的模型”翻译为“可以”混合 1.4 和 1.6 字节码,即使在类层次结构的特殊情况下也是如此。在我自己的小型 POC 项目和一些交叉手指的支持下,我宣布这个答案是可以接受的。谢谢彼得和所有人..
  • 从技术上讲,还有另一个打破类层次结构的变化——添加了 ACC_SUPER 标志。但这发生在 Java 1.4 之前,所以这应该不是问题。
【解决方案2】:

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

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

【讨论】:

  • 使用 1.4 代码级别的 JDK 6 编译将产生 1.4 兼容的字节码。我敢肯定这不会造成任何麻烦,因为所有字节码都是 1.4。问题是我们客户的旧(专有)开发工具集即将停产,他们想使用新工具集的花哨功能(需要注释等,因此将编译为 1.6 字节码)。
【解决方案3】:

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

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

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

不过,友情提醒,您在这里为自己挖了一个相当大的坑:-)

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

    • 新关键字是源级不兼容。编译的类不受影响。
    【解决方案5】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-20
      • 2011-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多