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 を削除しても安全です)。