12

私はこれをどこにも見たことがありません (または、単に見ないだけかもしれません) が、JNI を使用して c/c++ オブジェクトを返し、そのオブジェクトを Java で使用する方法はありますか?

例(非常に単純):

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

私のJavaコードでは、次のようなことをするにはどうすればよいですか:

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

これは非常に単純化された例であることは理解していますが、概念を探しているだけです.C ++で考えているクラスは非常に大きく、ラッパーメソッドのトンを作成しないようにしています...

それが不可能な場合は、数日コーディングを節約することを望んでいます笑

4

3 に答える 3

16

SimpleClass の Java バージョンは、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 を呼び出さなければならないため、メモリ リークの実際のリスクをもたらします。そうしないと、バッキング ネイティブ インスタンスが適切に破棄されない可能性があります。例で示したように、オーバーライドfinalizeしてネイティブの破壊者関数を呼び出すことはできますが、ファイナライズに依存できない方法に関するすべての警告は引き続き適用されます。破棄時に値を 0 に設定することでnativePtr、破棄が複数回呼び出された場合のセグ フォールトを回避できます (C++ では NULL を削除しても安全です)。

于 2012-04-18T15:58:35.237 に答える
5

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

今できることは、SWIG を使用して適切なラッパー メソッドを生成することです。これは実際に機能し、計画したよりも多くの作業は必要ありません :)

于 2012-04-18T15:38:43.780 に答える
0

JNI は、プリミティブ (またはかなりプリミティブ) 型のインターフェイスと、メモリ バッファーの受け渡し/管理関数のみを定義します。複雑なオブジェクト タイプをマップする機能はありません。ただし、 JNI を介して C++ クラスを Java に返す のように、独自の (単一の) シリアライゼーション/デシリアライゼーション関数を作成することで、この効果を達成できる場合があります。

于 2012-04-18T15:44:45.380 に答える