Java条件编译:如何防止代码块被编译?
我的项目需要Java 1.6进行编译和运行。 现在,我有一个要求使其与Java 1.5一起使用(从市场营销方面)。 我想替换方法主体(返回类型和参数保持相同),以使其在Java 1.5中编译时没有错误。
详细信息:我有一个名为ifdef, ifndef的实用程序类,它封装了所有特定于OS的内容。 它有一种方法
public static void openFile(java.io.File file) throws java.io.IOException {
// open the file using java.awt.Desktop
...
}
打开文件,就像双击一样(ifdef, ifndef Windows命令或hasattr Mac OS X命令等效项)。 由于无法使用Java 1.5进行编译,因此我想在编译期间将其排除,并替换为另一种方法,该方法使用2744943626802430430980(对于Windows而言为2744943626802430430979,对于Mac OS X是为2744943626802802430979)。
问题:我该怎么做? 注释可以在这里提供帮助吗?
注意:我使用ant,我可以制作两个java文件2744943626802430430和hasattr,其中将包含#+feature978类和Java 1.5和1.6所需的代码,然后在编译之前将其中一个复制到OS.java(或采用难看的方式-替换其中的内容)。 OS.java有条件地取决于Java版本),但如果有另一种方法,我也不想这样做。
详细说明:在C中我可以使用ifdef, ifndef,在Python中没有编译,并且可以使用hasattr或其他功能检查功能,在Common Lisp中,我可以使用#+feature。Java是否有类似的东西?
找到了这篇文章,但似乎没有帮助。
任何帮助是极大的赞赏。 kh。
9个解决方案
43 votes
不,Java不支持条件编译。
通常的计划是将应用的特定于操作系统的位隐藏在OS*之后,然后在运行时检测操作系统类型,并使用-source 1.5 -target 1.5加载实现。
在您的情况下,您没有理由不能同时使用Java 1.6和-source 1.5 -target 1.5编译两个2744944307168871871(并影响整个应用程序),然后在工厂方法中获取OS类(现在将是接口)检测到2744944307168871871427 类可用,并加载正确的版本。
就像是:
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 Davis answered 2020-02-12T23:12:29Z
18 votes
在Gareth建议的接口后面隐藏两个实现类可能是最好的方法。
就是说,您可以使用ant build脚本中的replace任务引入一种条件编译。 诀窍是在代码中使用注释,这些注释将在编译源代码之前通过文本替换打开/关闭,例如:
/*{{ 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进行编译时,将“ 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进行编译时,请替换“ IFDEF5”。 请注意,在/*{{、/*}}块内部使用2744944878288281280时要小心。
rsp answered 2020-02-12T23:13:03Z
7 votes
下面介绍的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脚本
请转到上面的链接以获取更多详细信息。
Youngjae answered 2020-02-12T23:13:40Z
5 votes
您可以使用反射进行调用,并使用Java 5编译代码。
例如
Class clazz = Class.forName("java.package.ClassNotFoundInJavav5");
Method method = clazz.getMethod("methodNotFoundInJava5", Class1.class);
method.invoke(args1);
您可以捕获任何异常,然后退回到适用于Java 5的东西。
Peter Lawrey answered 2020-02-12T23:14:09Z
5 votes
我不是一个出色的Java专家,但似乎Java中的条件编译受支持并且易于实现。 请阅读:
[http://www.javapractices.com/topic/TopicAction.do?Id=64]
引用要点:
有条件的编译实践用于有选择地从类的编译版本中删除代码块。 它利用编译器将忽略任何无法访问的代码分支这一事实。 要实施条件编译,
将静态的最终布尔值定义为某个类的非私有成员
将在有条件的if块中编译的位置代码,该块评估布尔值
将布尔值设置为false以使编译器忽略if块; 否则,保持其值为真实
当然,这使我们可以“编译”任何方法中的代码块。 要删除类成员,方法甚至整个类(可能只剩下一个存根),您仍然需要一个预处理器。
gregko answered 2020-02-12T23:15:01Z
5 votes
在Java 9中,可以创建多版本的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中,它将并且将找到并使用该类的最新版本。
bvdb answered 2020-02-12T23:15:35Z
4 votes
如果您不希望在应用程序中有条件地启用代码块,那么预处理器是唯一的方法,您可以看看可用于maven和ant项目的java-comment-preprocessor。
ps。
我也举了一些例子,说明如何在Maven中使用预处理功能来构建JEP-238多版本JAR,而无需复制源
Igor Maznitsa answered 2020-02-12T23:16:04Z
1 votes
Manifold框架中有一个新的Java预处理器。 这是一个javac插件,这意味着它直接与Java编译器集成在一起-没有构建步骤,没有代码生成目标等要管理。
Scott answered 2020-02-12T23:16:24Z
0 votes
Java Primitive Specializations Generator支持条件编译:
/* if Windows compilingFor */
start();
/* elif Mac compilingFor */
open();
/* endif */
该工具具有Maven和Gradle插件。
leventov answered 2020-02-12T23:16:48Z