Java条件编译:如何防止代码块被编译?
我的项目需要Java 1.6来编译和运行。现在我需要让它与 Java 1.5 一起工作(来自营销方面)。我想替换方法体(返回类型和参数保持不变)以使其使用 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 进行编译,因此我想在编译过程中排除它,并替换为另一种方法,该方法使用 调用 Windows 的
。run32dll
或 Mac OS X 的 open
运行时.exec
问题:我该怎么做?注释可以在这里提供帮助吗?
注意:我使用 ant,我可以制作两个 java 文件 OS4J5.java
和 OS4J6.java
,其中将包含 OS
类,其中包含 Java 1.5 和 1.6 所需的代码,并在编译之前将其中一个复制到 OS.java
(或一种丑陋的方式 - 替换 OS.java< 的内容) /code> 有条件地取决于java版本)但我不想这样做,如果有其他方法的话。
详细说明:在 CI 中可以使用 ifdef, ifndef
,在 Python 中没有编译,我可以使用 hasattr
或其他东西检查功能,在 Common Lisp 中我可以使用 <代码>#+功能。 Java 有类似的东西吗?
找到这篇文章,但它似乎没有帮助。
非常感谢任何帮助。 kh.
My project requires Java 1.6 for compilation and running. Now I have a requirement to make it working with Java 1.5 (from the marketing side). I want to replace method body (return type and arguments remain the same) to make it compiling with Java 1.5 without errors.
Details: I have an utility class called OS
which encapsulates all OS-specific things. It has a method
public static void openFile(java.io.File file) throws java.io.IOException {
// open the file using java.awt.Desktop
...
}
to open files like with double-click (start
Windows command or open
Mac OS X command equivalent). Since it cannot be compiled with Java 1.5, I want to exclude it during compilation and replace by another method which calls run32dll
for Windows or open
for Mac OS X using Runtime.exec
.
Question: How can I do that? Can annotations help here?
Note: I use ant, and I can make two java files OS4J5.java
and OS4J6.java
which will contain the OS
class with the desired code for Java 1.5 and 1.6 and copy one of them to OS.java
before compiling (or an ugly way - replace the content of OS.java
conditionally depending on java version) but I don't want to do that, if there is another way.
Elaborating more: in C I could use ifdef, ifndef
, in Python there is no compilation and I could check a feature using hasattr
or something else, in Common Lisp I could use #+feature
. Is there something similar for Java?
Found this post but it doesn't seem to be helpful.
Any help is greatly appreciated. kh.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
不,Java 中不支持条件编译。
通常的计划是将应用程序的操作系统特定位隐藏在
Interface
后面,然后在运行时检测操作系统类型并使用Class.forName(String)
加载实现。在您的情况下,没有理由不能使用 Java 1.6 和
-source 1.5 -target 1.5
编译两个OS*
(实际上是您的整个应用程序),然后在用于获取 OS 类(现在将是一个接口)的工厂方法检测到 java.awt.Desktop类可用并加载正确的版本。
像这样的东西:
Nope there isn't any support for conditional compilation in Java.
The usual plan is to hide the OS specific bits of your app behind an
Interface
and then detect the OS type at runtime and load the implementation usingClass.forName(String)
.In your case there no reason why you can't compile the both
OS*
(and infact your whole app) using Java 1.6 with-source 1.5 -target 1.5
then in a the factory method for getting hold ofOS
classes (which would now be an interface) detect thatjava.awt.Desktop
class is available and load the correct version.Something like:
像 Gareth 提议的那样,将两个实现类隐藏在一个接口后面可能是最好的方法。
也就是说,您可以使用 ant 构建脚本中的替换任务引入一种条件编译。诀窍是在代码中使用注释,这些注释在编译源代码之前通过文本替换打开/关闭,例如:
现在在 ant 中,当您编译 Java 6 时,将“IFDEF6”替换为“*/”,给出
:针对 Java 5 进行编译时,替换“IFDEF5”。请注意,在
/*{{
、/*}}
块内使用// comments
时需要小心。Hiding two implementation classes behind an interface like Gareth proposed is probably the best way to go.
That said, you can introduce a kind of conditional compilation using the replace task in ant build scripts. The trick is to use comments in your code which are opened/closed by a textual replacement just before compiling the source, like:
now in ant, when you compile for Java 6, replace "IFDEF6" with "*/", giving:
and when compiling for Java 5, replace "IFDEF5". Note that you need to be careful to use
// comments
inside the/*{{
,/*}}
blocks.您可以使用反射进行调用并使用 Java 5 编译代码。
例如,
您可以捕获任何异常并回退到可在 Java 5 上运行的内容。
You can make the calls using reflection and compile the code with Java 5.
e.g.
You can catch any exceptions and fall back to something which works on Java 5.
下面介绍的 Ant 脚本提供了漂亮而干净的技巧。
链接: https://weblogs.java.net/blog/schaefa /archive/2005/01/how_to_do_condi.html
例如
,使用 Ant 脚本
请访问上面的链接了解更多详细信息。
The Ant script introduced below gives nice and clean trick.
link: https://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html
in example,
with Ant script
please go to link above for more detail.
在 java 9 中,可以创建多版本 jar 文件。本质上,这意味着您创建同一个 java 文件的多个版本。
当你编译它们时,你用所需的jdk版本编译java文件的每个版本。接下来,您需要将它们打包成如下所示的结构:
在上面的示例中,代码的主要部分是在 java 8 中编译的,但对于 java 9,还有一个附加(但不同)版本的
Utils类。
当您在 java 8 JVM 上运行此代码时,它甚至不会检查 META-INF 文件夹中的类。但在 java 9 中它将查找并使用该类的更新版本。
In java 9 it's possible to create multi-release jar files. Essentially it means that you make multiple versions of the same java file.
When you compile them, you compile each version of the java file with the required jdk version. Next you need to pack them in a structure that looks like this:
In the example above, the main part of the code is compiled in java 8, but for java 9 there is an additional (but different) version of the
Utils
class.When you run this code on the java 8 JVM it won't even check for classes in the META-INF folder. But in java 9 it will, and will find and use the more recent version of the class.
如果您不想在应用程序中条件启用代码块,那么预处理器是唯一的方法,您可以查看 java-comment-preprocessor 可用于 maven 和 ant 项目
附:
我还制作了 一些示例如何使用 Maven 进行预处理来构建 JEP-238 多版本没有重复源的 JAR
if you don't want conditionally enabled code blocks in your application then a preprocessor is only way, you could take a look at java-comment-preprocessor which can be used for both maven and ant projects
p.s.
also I have made some example how to use preprocessing with Maven to build JEP-238 multi-version JAR without duplication of sources
我不是一个很好的 Java 专家,但似乎 Java 中支持条件编译并且很容易做到。请阅读:
http://www.javapractices.com/topic/TopicAction.do? Id=64
引用要点:
当然,这使我们可以在任何方法内“编译出”代码块。要删除类成员、方法甚至整个类(可能只留下一个存根),您仍然需要一个预处理器。
I'm not such a great Java expert, but it seems that conditional compilation in Java is supported and easy to do. Please read:
http://www.javapractices.com/topic/TopicAction.do?Id=64
Quoting the gist:
Of course this lets us to "compile out" chunks of code inside any method. To remove class members, methods or even entire classes (maybe leaving only a stub) you would still need a pre-processor.
Java Primitive Specializations Generator 支持条件编译:
该工具有 Maven 和 Gradle 插件。
Java Primitive Specializations Generator supports conditional compilation:
This tool has Maven and Gradle plugins.
嗨,当我在 Java SDK 和 Android 之间共享库并且在两种环境中都使用图形时,我遇到了类似的问题,所以基本上我的代码必须同时使用这两种环境
java.awt.Graphics 和 android.graphics.Canvas,
但我不想重复几乎任何代码。
我的解决方案是使用包装器,因此我间接访问 graphisc API,并且
我可以更改一些导入,以导入我想要编译项目的包装器。
这些项目有一些圆锥体阴影,有些是独立的,但除了几个包装纸等之外没有任何重复的东西。
我认为这是我能做的最好的事情。
hi I have got similar problem when I have shared library between Java SDK abd Android and in both environments are used the graphics so basically my code must to work with both
java.awt.Graphics and android.graphics.Canvas,
but I don't want to duplicate almost any code.
My solution is to use wrapper, so I access to graphisc API indirectl way, and
I can change a couple of imports, to import the wrapper I want to compile the projects.
The projects have some cone shaded and some are separate, but there is no duplicating anything except of couple of wrappers etc.
I think it is the best what I can do.