JVM を既存の C++ アプリケーションに埋め込んでおり、ネイティブ Java 関数の実装をクラスに登録する必要があります。
ネイティブ関数を持つこの単純なクラスを考えてみましょう:
class Native {
static {
System.out.println("Class 'Native' static initializer called.");
}
public native int f(int i);
}
JVM 内で OSGi を実行しているため、JNI からクラスをロードするのではなく、Java コードを使用して (正しいクラス ローダーを使用して) クラスを取得する必要があります。ただし、この例を単純にするために、OSGi は省略しています。
jclass
C++ で値を取得するために、次の 4 つの異なる Java メソッドがあります。
class Bridge {
public Class<?> getNativeClass1() throws ClassNotFoundException {
return getClass().getClassLoader().loadClass("org.example.Native");
}
public Class<?> getNativeClass2() throws ClassNotFoundException {
return Class.forName("org.example.Native", false, getClass().getClassLoader());
}
public Class<?> getNativeClass3() throws ClassNotFoundException {
final Class<?> clazz = getClass().getClassLoader()
.loadClass("org.example.Native");
clazz.getMethods();
return clazz;
}
public Class<?> getNativeClass4() throws ClassNotFoundException {
return Class.forName("org.example.Native", true, getClass().getClassLoader());
}
}
C++ でネイティブ関数の実装を登録するには、次のNative.f()
ように呼び出します。
JNIEnv* env = ...
jclass clazz = ...; // Calling one of the four methods above.
JNINativeMethod nativeMethod = {
(char*) "f", // Method name 'f'.
(char*) "(I)I;", // Signature 'int --> int'.
(void*) f // Pointer to C++ implementation of function.
};
env->RegisterNatives(clazz, &nativeMethod, 1);
Class<?>
インスタンスを取得するために使用する方法に応じて、異なる結果が得られます。
getNativeClass1()
Native
: クラスをロードするとき (もちろん、クラスのインスタンスを作成するとき) に静的初期化子がクラスで実行されず、ネイティブ実装が正しくバインドされません。(Java でネイティブ関数を呼び出すと、正しくない結果が返されるか、JVM がクラッシュします。)getNativeClass2()
: 同上。getNativeClass3()
Native
:クラスがロードされたときに静的イニシャライザはまだ呼び出されていませんが、ネイティブ実装は正しくバインドされており、正常に呼び出すことができますf()
。getNativeClass3()
:クラスがロードされ、ネイティブ実装が正しくバインドされると、静的初期化子がクラスで呼び出されます。Native
そのClassLoader.loadClass()
ため、適切に初期化されず、適切に機能しないようにクラスをロードしているようJNIEnv::RegisterNatives()
です。ただし、Class.getMethods()
ネイティブ メソッドのバインドが機能するように、呼び出すと何らかの方法でクラスが初期化されます (静的初期化子を呼び出さずに)。
一方、初期化されていないインスタンスを返すのとClass.forName(clazz, false, classLoader)
まったく同じように機能するようです。Class.loadClass()
Class
誰でも違いを説明できますか
getNativeClass1()
andによって返されるような初期化されていないクラスgetNativeClass2()
- によって返されるような部分的に初期化されたクラス
getNativeClass3()
- によって返されるような完全に初期化されたクラス
getNativeClass4()
を呼び出す前にクラスをロードする最も移植性の高い方法は何JNIEnv::RegisterNatives()
ですか?