Java条件编译:如何防止编译代码块?

我的项目需要Java 1.6进行编译和运行。 现在我有一个要求,使其与Java 1.5(从市场方面)的工作。 我想要replace方法体(返回types和参数保持不变),使其与Java 1.5编译没有错误。

详细信息:我有一个实用工具类称为OS封装所有操作系统特定的东西。 它有一个方法

 public static void openFile(java.io.File file) throws java.io.IOException { // open the file using java.awt.Desktop ... } 

双击打开文件( start Windows命令或open Mac OS X命令等效项)。 由于无法使用Java 1.5进行编译,因此我希望在编译过程run32dll其排除,并用另一种方法replace为Windows调用run32dll或使用Runtime.exec open Mac OS X。

问:我该怎么做? 注释可以帮助吗?

注意:我使用ant,并且可以创build两个java文件OS4J5.javaOS4J6.java ,它们将包含OS类与Java 1.5和1.6所需的代码,并将其中一个复制到OS.java编译之前(或丑陋方式 – 取决于java版本有条件地取代OS.java的内容),但我不想这样做,如果有另一种方式。

详细阐述:在CI中可以使用ifdef, ifndef ,在Python中没有编译,我可以使用hasattr或其他东西来检查一个特性,在Common Lisp中我可以使用#+feature 。 有什么类似的Java?

发现这篇文章,但它似乎没有帮助。

任何帮助是极大的赞赏。 KH。

不,在Java中没有任何对条件编译的支持。

通常的计划是在应用程序后面隐藏应用程序的操作系统特定位,然后在运行时检测操作系统types,并使用Class.forName(String)加载实现。

在你的情况下,没有任何理由不能使用Java 1.6和-source 1.5 -target 1.5编译OS* (实际上是你的整个应用程序),然后在工厂方法中获得OS类(现在将是一个接口)检测java.awt.Desktop类是否可用并加载正确的版本。

就像是:

  public interface OS { void openFile(java.io.File file) throws java.io.IOException; } public class OSFactory { public static OS create(){ try{ Class.forName("java.awt.Desktop"); return new OSJ6(); }catch(Exception e){ //fall back return new OSJ5(); } } } 

在Gareth提出的界面后面隐藏两个实现类可能是最好的方法。

也就是说,你可以在ant build脚本中引入一种使用replace任务的条件编译。 诀窍是在编译源代码之前在代码中使用通过文本replace来打开/closures的注释,如下所示:

 /*{{ Block visible when compiling for Java 6: IFDEF6 public static void openFile(java.io.File file) throws java.io.IOException { // open the file using java.awt.Desktop ... /*}} end of Java 6 code. */ /*{{ Block visible when compiling for Java 5: IFDEF5 // open the file using alternative methods ... /*}} end of Java 5 code. */ 

现在在ant中,当为Java 6编译时,用“* /”replace“IFDEF6”,给出:

 /*{{ Block visible when compiling for Java 6: */ public static void openFile(java.io.File file) throws java.io.IOException { // open the file using java.awt.Desktop ... /*}} end of Java 6 code. */ /*{{ Block visible when compiling for Java 5, IFDEF5 public static void openFile(java.io.File file) throws java.io.IOException { // open the file using alternative methods ... /*}} end of Java 5 code. */ 

并在为Java 5编译时,replace“IFDEF5”。 请注意,您需要小心使用/*{{/*}}块内的// comments

您可以使用reflection进行调用,并使用Java 5编译代码。

例如

 Class clazz = Class.forName("java.package.ClassNotFoundInJavav5"); Method method = clazz.getMethod("methodNotFoundInJava5", Class1.class); method.invoke(args1); 

你可以捕获任何exception,并回到Java 5上的一些东西。

下面介绍的Ant脚本给出了很好的干净的技巧。

链接: https : //weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html

在例子中,

 //[ifdef] public byte[] getBytes(String parameterName) throws SQLException { ... } //[enddef] 

用Ant脚本

  <filterset begintoken="//[" endtoken="]"> <filter token="ifdef" value="${ifdef.token}"/> <filter token="enddef" value="${enddef.token}"/> </filterset> 

请参阅上面的链接了解更多详情。

如果您不希望在您的应用程序中有条件启用的代码块,那么预处理器是唯一的方法,您可以看看可以用于Maven和Ant项目的java-comment-preprocessor
PS
我也做了一些例子,如何使用Maven预处理来构buildJEP-238多版本JAR,而不需要重复源代码

我不是一个很好的Java专家,但似乎在Java中的条件编译是支持和容易的。 请阅读:

http://www.javapractices.com/topic/TopicAction.do?Id=64

引用的要点:

条件编译实践用于可选地从类的编译版本中移除代码块。 它使用编译器将忽略任何不可达代码分支的事实。 要实施条件编译,

  • 定义一个静态的最终布尔值作为某个类的非私有成员
  • 放置代码,这个代码是有条件地编译在评估布尔值的if块中的
  • 将boolean的值设置为false以使编译器忽略if块; 否则,保持其值为真

当然,这让我们可以在任何方法中“编译”出大量的代码。 要删除类成员,方法甚至整个类(可能只留下一个存根),您仍然需要一个预处理器。

Java 9中 ,可以创build多版本的jar文件。 本质上,这意味着你可以制作同一个java文件的多个版本。

编译它们时,需要使用所需的jdk版本编译每个版本的java文件。 接下来,您需要将它们打包成一个如下所示的结构:

 + com + mypackage + Main.class + Utils.class + META-INF + versions + 9 + com + mypackage + Utils.class 

在上面的例子中,代码的主要部分是在java 8中编译的,但是对于java 9,还有一个额外的(但是不同的) Utils类的版本。

当你在java 8 JVM上运行这个代码时,它甚至不会检查META-INF文件夹中的类。 但在Java 9中,它将会,并且会find并使用更新版本的类。