我维护一个Java Swing应用程序。

为了向后兼容java 5(对于Apple机器),我们维护了两个代码库,一个使用Java 6中的功能,另一个没有这些功能。

除了使用Java 6功能的3-4个类之外,代码大致相同。

我希望只保留1个代码库。 在编译期间有没有办法让Java 5编译器“忽略”我代码的某些部分?

我不希望简单地评论/取消注释我的代码部分,具体取决于我的java编译器的版本。

===============>>#1 票数:5

关于使用自定义类加载器和动态注释代码的建议有点不可思议,当涉及到维护和保持灵性时,无论哪个可怜的灵魂在你洗牌到新的牧场后接受项目。

解决方案很简单。 将受影响的类拉出到两个独立的独立项目中 - 确保包名称相同,然后编译成可以在主项目中使用的jar。 如果保持包名称相同,并且方法签名相同,则没有问题 - 只需将您需要的jar版本放入部署脚本中即可。 我假设您在同一个脚本中运行单独的构建脚本或具有单独的目标 - ant和maven都可以轻松处理有条件地抓取文件并复制它们。

===============>>#2 票数:4

我认为这里最好的方法可能是使用构建脚本。 您可以将所有代码放在一个位置,通过选择要包含的文件以及不包含哪些文件,您可以选择要编译的代码版本。 请注意,如果您需要比每个文件更精细的控制,这可能没有用。

===============>>#3 票数:4 已采纳

假设类具有类似的功能,实现中的1.5与6.0差异,您可以将它们合并到一个类中。 然后,在不编辑注释/取消注释的源的情况下,您可以依赖编译器始终执行的优化。 如果if表达式始终为false,则if语句中的代码将不包含在编译中。

您可以在其中一个类中创建一个静态变量,以确定要运行的版本:

public static final boolean COMPILED_IN_JAVA_6 = false;

然后让受影响的类检查该静态变量,并将不同的代码段放在一个简单的if语句中

if (VersionUtil.COMPILED_IN_JAVA_6) {
  // Java 6 stuff goes here
} else {
  // Java 1.5 stuff goes here
}

然后,当您想要编译其他版本时,您只需更改该变量并重新编译即可。 它可能会使java文件变大,但它会整合您的代码并消除您拥有的任何代码重复。 您的编辑可能会抱怨无法访问的代码或其他什么,但编译器应该幸福地忽略它。

===============>>#4 票数:3

您可以重构代码,这样就不需要条件编译,只需要条件类加载。 像这样的东西:

public interface Opener{

public void open(File f);

 public static class Util{
        public Opener getOpener(){
          if(System.getProperty("java.version").beginsWith("1.5")){
           return new Java5Opener();
          }
          try{ 
            return new Java6Opener();
           }catch(Throwable t){
            return new Java5Opener();
           }
        }
 }

}

这可能需要付出很多努力,具体取决于您拥有多少版本特定的代码。

===============>>#5 票数:2

保留在JDK 5下构建的一个“主”源根。添加必须在JDK 6或更高版本下构建的第二个并行源根。 (应该没有重叠,即两者都不存在类。)使用接口来定义两者之间的入口点和一点点反射。

例如:

---%<--- main/RandomClass.java
// ...
if (...is JDK 6+...) {
    try {
        JDK6Interface i = (JDK6Interface)
            Class.forName("JDK6Impl").newInstance();
        i.browseDesktop(...);
    } catch (Exception x) {
        // fall back...
    }
}
---%<--- main/JDK6Interface.java
public interface JDK6Interface {
    void browseDesktop(URI uri);
}
---%<--- jdk6/JDK6Impl.java
public class JDK6Impl implements JDK6Interface {
    public void browseDesktop(URI uri) {
        java.awt.Desktop.getDesktop().browse(uri);
    }
}
---%<---

您可以使用不同的JDK等将它们配置为IDE中的单独项目。关键是主根可以独立编译,并且非常清楚您可以在哪个根中使用,而如果您尝试编译的不同部分单独的根分开很容易将JDK 6的使用“泄漏”到错误的文件中。

您可以使用某种服务注册系统 - java.util.ServiceLoader(如果main可以使用JDK 6,并且您需要对JDK 7的可选支持!),NetBeans Lookup,Spring等,而不是像这样使用Class.forName。等等

可以使用相同的技术来创建对可选库的支持,而不是新的JDK。

===============>>#6 票数:1

不是真的,但有一些解决方法。 请参阅http://forums.sun.com/thread.jspa?threadID=154106&messageID=447625

也就是说,你应该坚持至少拥有一个用于Java 5的文件版本和一个用于Java 6的文件版本,并通过构建或适当的方式包含它们。 将它全部放在一个大文件中并尝试让编译器为5来忽略它不理解的东西并不是一个好的解决方案。

HTH

- nikki -

===============>>#7 票数:1

这将使所有Java纯粹主义者感到畏缩(这很有趣,嘿嘿)但我会使用C预处理器,将#ifdefs放在我的源代码中。 makefile,rakefile或任何控件构建都必须运行cpp来生成一个临时文件来提供编译器。 我不知道蚂蚁是否可以做到这一点。

虽然stackoverflow看起来像是所有答案地方,但你可能没有人看到http://www.javaranch.com的Java智慧。 我想这个问题已经在那里得到了解决,很久以前。

===============>>#8 票数:1

这取决于您要使用的Java 6功能。 对于像向JTables添加行分类器这样的简单操作,您可以在运行时实际测试:

private static final double javaVersion =
         Double.parseDouble(System.getProperty("java.version").substring(0, 3));
private static final boolean supportsRowSorter =
         (javaVersion >= 1.6);

//...

if (supportsRowSorter) {
    myTable.setAutoCreateRowSorter(true);
} else {
    // not supported
}

此代码必须使用Java 6编译,但可以使用任何版本运行(不引用新类)。

编辑:更正确,它将适用于1.3以来的任何版本(根据此页面 )。

===============>>#9 票数:1

您可以在Java6上完成所有编译,然后使用System.getProperty(“java.version”)有条件地运行Java5或Java6代码路径。

您可以在类中使用仅Java6代码,只要不执行仅Java6代码路径,该类就可以在Java5上正常运行。

这是一个技巧,用于编写将在古老的MSJVM上运行的applet,直到全新的Java Plug-in JVM。

===============>>#10 票数:0

您可以使用反射API。 将所有1.5代码放在一个类中,将1.6 api放在另一个类中。 在你的ant脚本中创建两个目标,一个用于1.5,不能编译1.6类,另一个用于1.6,不能编译1.5的类。 在你的代码中检查你的java版本并使用反射加载适当的类,javac不会抱怨缺少函数。 这就是我如何在Windows上编译我的MRJ(Mac Runtime for Java)应用程序。

===============>>#11 票数:0

Java中没有预编译器。 因此,无法在C中执行#ifdef。构建脚本将是最好的方法。

===============>>#12 票数:0

你可以得到条件编译,但不是很好 - javac将忽略无法访问的代码。 因此,如果您正确构建了代码,则可以让编译器忽略部分代码。 要正确使用它,您还需要将正确的参数传递给javac,以便它不会将无法访问的代码报告为错误,并拒绝编译:-)

===============>>#13 票数:0

上面提到的公共静态最终解决方案还有一个额外的好处,作者没有提到 - 据我所知,编译器将在编译时识别它并编译出引用该最终变量的if语句中的任何代码。

所以我认为这是您正在寻找的确切解决方案。

===============>>#14 票数:0

一个简单的解决方案是:

  • 将发散类放在正常类路径之外。
  • 编写一个简单的自定义类加载器并将其安装在main中作为默认值。
  • 对于除5/6之外的所有类,cassloader可以推迟到其父级(普通系统类加载器)
  • 对于5/6的(它们应该是父母无法找到的唯一的),它可以通过'os.name'属性或您自己的属性来决定使用哪个。

  ask by Merv translate from so

未解决问题?本站智能推荐:

1回复

为什么此代码将在eclipse中编译,但不能在jGrasp中编译

我决定参加一个Java类,教授希望所有.java文件都在jGrasp中运行,但是我对eclipse更为熟悉,因此我一直在使用它。 我有两个可以在Eclipse中正常编译的文件,但是当我在jGrasp中打开其.java文件时,它们要么无法正确执行,要么某些导入语句会导致错误。 这将编译,但
1回复

编译时出错[重复]

这个问题已经在这里有了答案: 类,接口或枚举预期的错误 2个答案 基本上,这是客户端聊天Java应用程序的服务器端。 在编译过程中会发生如下这样的错误: 请帮助消除错误。
1回复

同一包中的类不能互相看到,也不能在终端中编译

这两个类(MainClass和Login)位于同一包(mainPackage)中。 在netbeans IDE上,应用程序可以正常运行(编译和执行)。 但是当使用Terminal编译MainClass时,出现此错误: 错误:找不到符号 符号:类登录 这是我的目录
1回复

使用条件语句从JTextArea读取和编译行[重复]

这个问题已经在这里有了答案: 如何计算以字符串形式给出的数学表达式? [已关闭] 24个答案 大家早上好,我是Java编程的初学者。 因此,直截了当,我正在创建一个程序,单击一下按钮即可读取和编译.txt文件。 我已经读完文件了。 我的问题是我的程序没有
1回复

如何分发Java GUI构建器项目

这个问题已经在这里有了答案: Java Path ImageIcon URL .JAR 1回答 目前,我分发了其他代码,以从Java运行时环境中获取“发生Java异常”。 我将如何以.jar的形式正确分发? 这是显示我的项目文件和类路径的屏幕截图
2回复

运行旧的Java程序

几年前,我写了很多简单的Java小程序……我已经有一段时间没有用过了,我想回去修改它们。 我相信我将Netbeans用作我的IDE(但是我也可以使用Eclipse。。。 总之长话短说...。我不记得如何编译它们,也无法在我的任何IDE中将它们作为项目打开。 我试过使用javac ,
4回复

有没有办法在编译期间在Java类中使用maven属性

我只是想在编译时在我的Java类中使用maven占位符以减少重复。 像这样的东西: 的pom.xml SomeVersion.java
1回复

有没有办法在Java编译过程中包含Antlr?

我正在使用Antlr4创建Java(Java 7)源转换工具。 我将Main.java文件作为输入,并将其转换为输出newMain.java源文件,该文件对应于相同的程序,但有少量更改。 要运行我的转换工具,我使用导出的generator.jar文件,如下所示: 步骤1(我使用gene
2回复

有没有办法在在线编译器中创建JFrame?

我已经使用NetBeans IDE 8.2创建Java程序已有一段时间了,并且没有遇到任何麻烦。 我试图找到一个允许我创建JFrame的在线编译器,但是我通常会收到错误消息: 我尝试了几种不同的在线编译器,还研究了X11 DISPLAY,但没有发现任何有用的东西。 有没有一种方
1回复

为什么我不能在CMD上编译此简单的Java代码,而在在线编译器上进行编译?

我从一本书(名为Schaum的《计算机科学原理纲要》)中获得了以下Java代码: 我已将“原始”更改为“主要”。 可以在此网站上进行编译: http://www.learnjavaonline.org/ 输出仅为“ x = 11”。 但是,当尝试使用javac Mai