2012-04-18 12 views
11

私はこれを見たことがありませんでした(または、おそらく私はそれを見ていないシンプルなjsutです)ですが、JNIを使​​用してc/C++オブジェクトを返し、そのオブジェクトをJavaで使用する方法はありますか?例えばJNIを使​​用してJavaコード内のC++オブジェクトを参照できますか?

(非常にシンプル):私はのようなものをやって行くだろうか、私のJavaコードでは、

class simpleClass{ 
... 
private: 
int intVar; 
public: 
int getIntVar(); 
void setIntVar(int someNum); 
... 
} 

... 
simpleClass sc = new simpleClass(); 
sc.setIntVar(9); 
System.out.println(sc.getIntVar()); 
... 

私はこれは非常に単純化した例である実現が、私は」私はちょうどコンセプトを探しています - 私はC++であることを念頭に置いているクラスは非常に大きく、ラッパーメソッドのトーンを作成することを避けるために探しています...

それはうまくいかない場合は、あなたのコードを保存する数日を節約する

答えて

7

いいえできません。 C++とJavaのABIは全く異なっています.1つはC++で定義されていません。そして本当にC++には、Javaにマッピングできない非常に多くの機能がありますが、これらはすべて機能しません。 JavaがC++テンプレートをどのように処理すると思いますか?プリミティブへのポインタ? のオブジェクトはポインタではありませんか?

は今、あなたは何ができるか、あなたのための右のラッパー・メソッドを生成するために使用SWIGである - 実際に動作し、あなたが計画:)

JNIがプリミティブのためのインタフェースを定義する
+4

テンプレートはC++でコンパイルされているので、C++テンプレートはこの質問とは無関係です。 JNIは、これらのテンプレートからインスタンス化されたクラスをサポートする必要があります。これは通常のクラスと変わりません。 –

+0

@ダンヘッダーのみのテンプレートクラスを記述している場合、クライアントコードで新しいバージョンのクラスをインスタンス化するようにコンパイラに指示する必要があります。したがって、コンパイラはテンプレートについても知っておく必要があります標準で要求されているかどうかは考えられませんが、現実にはこれを行う必要はありませんでした)。 – Voo

+0

@Vooインスタンス化を生成するには、コンパイル時にテンプレートの定義が必要です。使用される必要な型ごとに生成されると、オブジェクトコードはそれぞれの型のクラスを書き出したかのようになります。 AFAIKにcppファイルを含めないと、同じ理由で定義が完全にインラインでない限り、翻訳単位にないテンプレートは参照できません。 – AJG85

0

(または何よりもはるかに多くの作業ではありませんかなりプリミティブな)型だけでなく、メモリー・バッファの受け渡し/管理機能も提供します。複雑なオブジェクト型をマップする機能はありません。ただし、Returning a C++ class to Java via JNIのように、独自の(単一の)シリアライズ/デシリアライズ関数を記述することで、この効果を得ることができます。

+0

興味深い...これは非常に興味深い概念です。私はリンクを感謝します!ありがとう! – redhotspike

12

JavaクラスのSimpleClassは、2つのことを行う必要があります。 1つは、バックネイティブのネイティブオブジェクトへのC++ポインタの値を格納するプライベートのlong値を保持します(ネイティブポインタの大きさに応じてBigIntegerを使用する必要があります - unsigned long long?)。 2つ目は、パブリックメソッド(例:setIntVal)をネイティブにします。

public class SimpleClass { 
    private long nativePtr; 

    public SimpleClass() { 
     nativePtr = initNativeSimpleClass(); 
    } 

    public void destroy() { 
     destroyNativeSimpleClass(); 
     nativePtr = 0L; 
    } 

    protected void finalize() throws Throwable { 
     destroyNativeSimpleClass(); 
     nativePtr = 0L; 
    } 

    public native int getIntVal(); 
    public native void setIntVal(int val); 

    private native long initNativeSimpleClass(); 
    private native void destroyNativeSimpleClass(); 
} 

次に、これらのネイティブメソッドをJNIコードで実装します。 initNativeSimpleClass()メソッドは新しいのバッキングC++インスタンスSimpleClassになります。 destroyNativeSimpleClass()メソッドはそのインスタンスを削除します。アクセサメソッドはnativePtrの値を使用し、それを実際のポインタにキャストし、ネイティブバッキングインスタンスに対して適切な操作を実行します。

このイディオムは、インスタンスの終了時にクラスのユーザーがdestroyを呼び出さなければならないため、メモリがリークするリスクがあります。そうでない場合、元のネイティブインスタンスが適切に破棄されないことがあります。この例で示したように、ネイティブのdestroyer関数を呼び出すには、finalizeをオーバーライドすることができますが、ファイナライズの仕方についてのすべての注意事項は依然として適用されます。破棄時にnativePtrの値を0に設定すると、destroyが複数回呼び出された場合にsegフォルトが回避されます(C++ではNULLを削除するのが安全です)。

+0

これはラッパー関数の作成を避けますが、JNIを使​​用してJavaフロントをネイティブクラスに配置する唯一の方法です。 – pedorro

+0

私はこれが私が提案したものを受け入れることを間違いなく望んでいます...私はがC++オブジェクトを「使用している」よりもこのように優れていると言わなければならない:それはネイティブメソッドを使用していることを文書化する方法を提供する。ありがとう! – redhotspike

関連する問題