【问题标题】:Java: easiest way to package both Java 1.5 and 1.6 codeJava:打包 Java 1.5 和 1.6 代码的最简单方法
【发布时间】:2010-03-15 16:11:56
【问题描述】:

我想打包一段绝对必须在 Java 1.5 上运行的代码。如果 VM 是 1.6 VM,则可以在代码的一部分中“增强”程序。

基本上就是这个方法:

 private long[] findDeadlockedThreads() {
    // JDK 1.5 only supports the findMonitorDeadlockedThreads()
    // method, so you need to comment out the following three lines
    if (mbean.isSynchronizerUsageSupported())
      return mbean.findDeadlockedThreads();
    else
      return mbean.findMonitorDeadlockedThreads();
  }

在 1.5 上编译而在 1.6 上执行 1.6 方法调用的最简单方法是什么?

在过去,我通过编译一个独特的 1.6 类来完成类似的操作,我将在 1.6 上使用 ClassLoader 将它与我的应用程序打包并实例化(因为 1.6 JVM 非常适合混合 0x32 和 0x31 类),但我认为这有点矫枉过正(而且有点痛苦,因为在构建过程中您必须同时构建 0x31 和 0x32 .class 文件)。

如果我想在1.5上编译上面的方法应该怎么做?也许使用反射,然后如何(我对反射一点也不熟悉)

注意:如果你好奇,上面的方法来自这篇文章:http://www.javaspecialists.eu/archive/Issue130.html

(但我不想像文章中那样“评论三行”,我希望它能够在 1.5 和 1.6 上编译和运行)

【问题讨论】:

    标签: java class java-6 java-5


    【解决方案1】:

    你不能在 1.5 上编译它,但你可以在 1.6 上编译,目标选项设置为 1.5(这将产生 1.5 的字节码)并在代码中使用反射来确定该方法是否可用。

    此代码将查找方法: mbean.getClass().getMethod("findDeadlockedThreads", new Class[0]); 问题是,如果方法不存在,它会抛出 NoSuchMethodException 而不是简单地返回 null 或类似的东西。这意味着,您需要这样的代码:

    try
    {
      mbean.getClass().getMethod("findDeadlockedThreads", new Class<?>[0]);
      return mbean.findDeadlockedThreads();
    }
    catch(NoSuchMethodException ex)
    {
      return mbean.findMonitorDeadlockedThreads();
    }
    

    这不是很好,因为它使用异常来做出决定。这可能不是很快。另一种方法是使用 getMethods 并在您的方法可用时迭代返回的列表。这也不是很快。

    编辑: Christopher Oezbek 在 cmets 中建议只检查一次方法是否存在并保存结果以避免 Try-catch-block 的开销。这是正确的,也是一个很好的解决方案。 matt b 警告说,Java-Compiler 的 target-option 不会检查所使用的类和方法是否在 Java 1.5 下可用。没错(否则它将无法工作,因为您想针对 1.6 方法进行编译),这意味着该程序应在 1.5-VM 下仔细测试,以避免此问题。谢谢你们两位的cmets。

    【讨论】:

    • @Mnementh:好的,但是反射代码会是什么样子?
    • @Mnementh:+1 太棒了...我会在今天下午尝试设置:)
    • @Mnementh 您可以使用一个标志来缓存 getMethod 检查的结果,并将此结果用于所有未来的情况。这避免了 NoSuchMethodException 的性能开销。
    • @Christopher Oezbek:感谢您的评论,在阅读您的评论之前我就是这样做的(在阅读了 danpaq 建议在构造函数中设置 Method refs 之后)。
    • 在 1.6 上编译 target=1.5 会带来使用仅在 1.6 中可用的其他方法/类的危险,因为如果您使用 1.6 而不是 1.5 中可用的类/方法,编译器不会警告您。
    【解决方案2】:

    为 1.5 编译。

    在您的代码中使用反射。可以从 Class 接口获取 Method 对象;它有一个将您的 mbean 实例作为参数的调用方法。像这样的:

    类 c = mbean.getClass(); // 也可以做YourClass.class来得到这个

    方法 m = c.getMethod("findMonitorDeadLockedThreads"); // 或任何其他方法(参数 方法是用 Class 指定的... getMethod 的第二个参数)

    m.invoke(mbean) // 使用您的实例调用方法

    当然,您不必每次都这样做;在构造函数中设置方法引用,然后按需调用正确的引用。

    【讨论】:

    • @danpaq:这是一个简单的情况,因为没有参数可以传递给该方法。因此,从 Mnementh 和您的回答中,我认为反思是要走的路……所以我会尝试您在此处提出的建议。
    • @WizardOfOdds:如果您认为此建议有价值,请点赞。
    【解决方案3】:

    Maven 让您可以通过配置文件轻松完成此操作。配置文件背后的想法是,您希望根据某些标准构建事物的两个不同版本。在这个特定示例中,您可以定义一个jdk15 和一个jdk16 配置文件,指定使用哪个JDK 版本进行编译,并告诉它在jdk15 配置文件中包含该类的一个副本,在jdk16 中包含另一个副本。

    要开始使用,请参阅:

    http://unserializableone.blogspot.com/2008/09/compile-and-test-with-different-jdk.html

    这描述了如何处理不同的JDK版本部分的问题。

    要处理问题的第二部分,根据 JDK 版本使用不同的类定义,请参见:

    Maven - Include Different Files at Build Time

    【讨论】:

    • 抱歉,希望对您有所帮助...我现在没有时间向您展示完整的 maven 构建脚本。
    • 只是为了确保我理解你所说的正确:我需要打包和运送一个独特的 .jar 工作在 1.5 和 1.6 上,在 1.6 上使用 1.6 功能,我可以使用 Maven 配置文件执行此操作吗?
    • @WizardOfOdds:是的,这就是我之前试图描述的。我修改了我的回复,添加了描述如何做到这一点的链接,比我在这里描述的要好。
    猜你喜欢
    • 1970-01-01
    • 2012-05-19
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    • 2013-06-24
    • 2021-11-11
    相关资源
    最近更新 更多