9

特定のライブラリが含まれている場合、コードが必要なライブラリを作成しています。このコードはプロジェクト全体に散らばっているので、ユーザーが自分ですべてをコメント/コメント解除する必要がなければいいでしょう。

#defineC では、これはヘッダーに a があり、コード ブロックが で囲まれているので簡単#ifdefsです。もちろん、Java には C プリプロセッサがありません...

明確にするために、いくつかの外部ライブラリが私のものと一緒に配布されます。実行可能サイズを最小限に抑えるために、それらすべてを含める必要はありません。開発者がライブラリを含める場合は、それを使用できるようにする必要があります。そうでない場合は、無視してかまいません。

Javaでこれを行う最良の方法は何ですか?

4

13 に答える 13

11

Java 内からやりたいことを行う方法はありません。Java ソース ファイルを前処理することもできますが、それは Java の範囲外です。

違いを抽象化して、実装を変えることはできませんか?

あなたの明確化に基づいて、外部ライブラリの1つからのオブジェクト、または「利用できない」で行ったであろうことを関数が行う「スタブ」クラスのいずれかを返すファクトリメソッドを作成できるように思えます" 条件付きコード。

于 2009-12-21T22:25:54.813 に答える
5

Java では、さまざまなアプローチを使用して同じ結果を得ることができます。

Java の方法では、さまざまな動作をインターフェイスを介して抽象化された一連の個別のクラスに入れ、実行時に必要なクラスをプラグインします。以下も参照してください。

于 2009-12-21T22:38:59.637 に答える
4

Java 構文は C に十分近いため、通常は別の実行可能ファイルとして出荷される C プリプロセッサを簡単に使用できます。

しかし、Java は実際にはコンパイル時に何かを行うわけではありません。私が以前に同様の状況に対処した方法は、リフレクションです。あなたの場合、おそらく存在しないライブラリへの呼び出しがコード全体に散らばっているので、ラッパークラスを作成し、ライブラリへのすべての呼び出しをラッパークラスへの呼び出しに置き換えてから、ラッパークラス内でリフレクションを使用しますライブラリが存在する場合はライブラリで呼び出します。

于 2009-12-21T22:49:05.293 に答える
2

定数を使用します:

今週は、C プリプロセッサの機能を使用してコンパイル時の定数と条件付きでコンパイルされたコードを定義する利点をすべて備えた定数をいくつか作成します。

Java は、テキスト プリプロセッサの概念全体を取り除きました (Java を C/C++ の「子孫」と見なす場合)。ただし、Java の C プリプロセッサの機能の少なくとも一部 (定数と条件付きコンパイル) の最大の利点を得ることができます。

于 2009-12-21T22:23:04.773 に答える
1

「実行可能ファイルのサイズを最小化するには」

「実行可能サイズ」とはどういう意味ですか?

実行時にロードされるコードの量を意味する場合は、クラスローダーを介して条件付きでクラスをロードできます。したがって、何があっても代替コードを配布しますが、実際にロードされるのは、それが代用するライブラリがない場合のみです。アダプター (または同様のもの) を使用して API をカプセル化し、ほとんどすべてのコードがどちらの方法でもまったく同じであることを確認し、ケースに応じて 2 つのラッパー クラスのいずれかが読み込まれるようにすることができます。Java セキュリティ SPI は、これをどのように構造化して実装するかについてのアイデアを提供してくれるかもしれません。

.jar ファイルのサイズを意味する場合は、上記を行うことができますが、不要なクラスが不要であることがわかっている場合に備えて、jar から不要なクラスを削除する方法を開発者に伝えてください。

于 2009-12-21T22:43:12.780 に答える
1

もう1つ良い言い方があります。

必要なのは final 変数です。

public static final boolean LibraryIncluded= false; //or true - manually set this

次に、コード内で次のように言います

if(LibraryIncluded){
    //do what you want to do if library is included
}
else
{
    //do if you want anything to do if the library is not included
}

これは #ifdef として機能します。ブロックのいずれかが実行可能コードに存在します。その他はコンパイル時に削除されます

于 2015-01-23T18:32:23.813 に答える
1

私は本当にそのようなことがあるとは信じていません。ほとんどの真の Java ユーザーは、これは良いことであり、条件付きコンパイルに依存することは何としてでも避けるべきだと言うでしょう。

私は彼らに本当に同意しません...

コンパイル行から定義できる定数を使用できます。これにより、一部の効果が得られますが、実際にはすべてではありません。(たとえば、コンパイルされないものを #if 0 内に含めることはできませんが、それでも必要です... (いいえ、ネストされたコメントはトリッキーになる可能性があるため、コメントが常にその問題を解決するとは限りません... )))。

ほとんどの人は、これを行うためになんらかの形式の継承を使用するように言うと思いますが、それは非常に醜く、多くのコードが繰り返される可能性があります...

そうは言っても、Java を javac に送信する前にプリプロセッサを介して Java をスローするように IDE を設定することはいつでもできます...

于 2009-12-21T22:31:01.633 に答える
0

あなたがしていることに応じて(十分な情報ではありません)、次のようなことができます:

interface Foo
{
    void foo();
}

class FakeFoo
    implements Foo
{
   public void foo()
   {
       // do nothing
   }
}

class RealFoo
{
    public void foo()
    {
        // do something
    }
}

次に、インスタンス化を抽象化するクラスを提供します。

class FooFactory
{
    public static Foo makeFoo()
    {
        final String   name;
        final FooClass fooClass;
        final Foo      foo;

        name     = System.getProperty("foo.class");
        fooClass = Class.forName(name);
        foo      = (Foo)fooClass.newInstance();

        return (foo);
    }
}

次に、-Dfoo.name=RealFoo|FakeFoo を指定して Java を実行します。

makeFoo メソッドの例外処理を無視し、他の方法で実行できます...しかし、考え方は同じです。

このようにして、Foo サブクラスの両方のバージョンをコンパイルし、開発者が実行時にどちらを使用するかを選択できるようにします。

于 2009-12-22T01:24:22.253 に答える
0

j2me ポリッシュまたはBlackBerry JDE プラグインの eclipse でのプリプロセッサ ディレクティブの使用を参照してください。

これはモバイルアプリ用ですが、これは再利用できますか?

于 2010-01-20T14:53:07.533 に答える
0

この種のことを行うには、プロパティを使用します。

Class.forName などを使用してクラスを識別します。

プロパティを直接クラスに簡単に変換できる場合は、if ステートメントを使用しないでください。

于 2009-12-21T22:25:14.833 に答える
0

ここで、相互に排他的な 2 つの問題を指定しているのが見えます (または、どちらかを選択した可能性が高く、どちらを選択したのかわかりません)。

ソース コードの 2 つのバージョン (ライブラリが存在する場合とそうでない場合) を出荷するか、単一のバージョンを出荷し、ライブラリが存在する場合はライブラリで動作することを期待するかを選択する必要があります。 .

単一のバージョンでライブラリの存在を検出し、利用可能な場合はそれを使用する場合は、分散コードにアクセスするためのすべてのコードが必要です。削除することはできません。あなたの問題を #define の使用と同一視しているので、これはあなたの目標ではないと思いました.2 つのバージョンを出荷したいのです (#define が機能する唯一の方法です)。

したがって、2 つのバージョンで libraryInterface を定義できます。これは、ライブラリをラップし、すべての呼び出しをライブラリまたはインターフェイスに転送するオブジェクトのいずれかです。どちらの場合も、このオブジェクトは両方のモードでコンパイル時に存在する必要があります。

public LibraryInterface getLibrary()
{
    if(LIBRARY_EXISTS) // final boolean
    {
        // Instantiate your wrapper class or reflectively create an instance             
        return library; 
    }
    return null;
}

ライブラリを使用したい場合 (C で #ifdef を使用した場合)、次のようになります。

if(LIBRARY_EXISTS)
    library.doFunc()

ライブラリは、どちらの場合にも存在するインターフェイスです。これは常に LIBRARY_EXISTS によって保護されているため、コンパイルされます (クラス ローダーに読み込まれることさえありませんが、これは実装に依存します)。

ライブラリがサード パーティによって提供される事前にパッケージ化されたライブラリである場合、Library をその呼び出しをライブラリに転送するラッパー クラスにする必要がある場合があります。LIBRARY_EXISTS が false の場合、ライブラリ ラッパーはインスタンス化されないため、実行時にロードすることさえできません (JVM が常に final 定数によって保護されているため、JVM が十分にスマートな場合はコンパイルすることさえできません)。ただし、覚えておいてください。どちらの場合も、コンパイル時にラッパーを使用できる必要があります。

于 2009-12-22T18:32:22.857 に答える