54

私のプロジェクトでは、コンパイルと実行にJava1.6が必要です。今、私はそれをJava 1.5で動作させるための要件が​​あります(マーケティング側から)。メソッド本体を置き換えて(戻り値の型と引数は同じままです)、エラーなしでJava1.5でコンパイルできるようにします。

詳細:OS OS固有のものをすべてカプセル化するというユーティリティクラスがあります。方法があります

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

ダブルクリックのようにファイルを開くには(startWindowsコマンドまたはopenMac OS Xコマンドと同等)。Java 1.5ではコンパイルできないので、コンパイル時に除外しrun32dll、WindowsまたはopenMacOSXを使用して呼び出す別のメソッドに置き換えたいと思いRuntime.execます。

質問:どうすればそれができますか?注釈はここで役立ちますか?

注:私はantを使用しており、2つのJavaファイルOS4J5.javaを作成できます。このファイルには、Java 1.5および1.6に必要なコードをOS4J6.java含むクラスが含まれ、コンパイルする前にそのうちの1つをコピーします(または醜い方法-Javaに応じて条件付きでコンテンツを置き換えます)バージョン)しかし、別の方法がある場合、私はそれをしたくありません。OSOS.javaOS.java

さらに詳しく説明すると、CIifdef, ifndefではを使用できます。Pythonではコンパイルは行われず、または他の何かを使用して機能をチェックhasattrできます。CommonLispではを使用できます#+feature。Javaに似たものはありますか?

この投稿が見つかりましたが、役に立たないようです。

どんな助けでも大歓迎です。kh。

4

10 に答える 10

43

いいえ、Javaでは条件付きコンパイルはサポートされていません。

通常の計画は、アプリのOS固有のビットを背後に隠してからInterface、実行時にOSタイプを検出し、を使用して実装をロードすることClass.forName(String)です。

OS*あなたの場合、Java 1.6を使用して両方をコンパイルできない(そして実際にはアプリ全体をコンパイルできない)理由はありません-source 1.5 -target 1.5。ファクトリメソッドで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();
         }
     }
 }
于 2010-12-24T11:47:46.223 に答える
18

Gareth が提案したようなインターフェイスの背後に 2 つの実装クラスを隠すことが、おそらく最善の方法です。

つまり、ant ビルド スクリプトで 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」を置き換えます。,ブロック// comments内での使用には注意が必要です。/*{{/*}}

于 2010-12-24T12:35:55.890 に答える
6

リフレクションを使用して呼び出しを行い、Java 5 でコードをコンパイルできます。

例えば

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

例外をキャッチして、Java 5 で動作するものにフォールバックできます。

于 2010-12-24T11:53:09.057 に答える
6

以下に紹介する 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>

詳細については、上記のリンクを参照してください。

于 2013-12-27T08:41:09.777 に答える
5

私は Java の専門家ではありませんが、Java での条件付きコンパイルはサポートされており、簡単に実行できるようです。読んでください:

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

要旨を引用:

条件付きコンパイルのプラクティスは、コンパイルされたバージョンのクラスからオプションでコードのチャンクを削除するために使用されます。これは、コンパイラがコードの到達不能な分岐を無視するという事実を利用しています。条件付きコンパイルを実装するには、

  • static final ブール値をクラスの非プライベート メンバーとして定義する
  • 条件付きでコンパイルされるコードを、ブール値を評価する if ブロックに配置します。
  • ブール値を false に設定して、コンパイラが if ブロックを無視するようにします。それ以外の場合は、その値を true のままにします

もちろん、これにより、任意のメソッド内のコードのチャンクを「コンパイル」できます。クラス メンバー、メソッド、またはクラス全体を削除するには (おそらくスタブのみを残す)、プリプロセッサが必要です。

于 2016-05-27T23:21:43.113 に答える