Javaでは、Objectクラスのprivate staticメソッドregisterNatives()は何をしますか?
3 に答える
他の回答は技術的には正しいですが、JNI の経験がない人にとってはあまり役に立ちません。:-)
通常、JVM がネイティブ関数を見つけるには、特定の方法で名前を付ける必要があります。たとえば、 for のjava.lang.Object.registerNatives場合、対応する C 関数の名前はJava_java_lang_Object_registerNativesです。registerNatives(というか、JNI 関数) を使用RegisterNativesすることで、C 関数に好きな名前を付けることができます。
関連する C コードは次のとおりです (OpenJDK 6 から)。
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode},
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
(*env)->RegisterNatives(env, cls,
methods, sizeof(methods)/sizeof(methods[0]));
}
( はリストにないことに注意しObject.getClassてください。これは引き続き の「標準」名で呼び出されJava_java_lang_Object_getClassます。) リストされた関数については、関連する C 関数がその表にリストされているとおりであり、転送関数の束を記述するよりも便利です。
ネイティブ関数の登録は、Java を C プログラムに組み込み、(共有ライブラリ内ではなく) アプリケーション自体内の関数にリンクしたい場合、または使用されている関数が「エクスポート」されない場合にも役立ちます。通常、標準のメソッド ルックアップ メカニズムでは検出されません。ネイティブ関数の登録は、ネイティブ メソッドを別の C 関数に「再バインド」するためにも使用できます (たとえば、プログラムがモジュールの動的なロードとアンロードをサポートしている場合に役立ちます)。
JNIの書籍 を読むことをお勧めします。この本では、このことやその他多くのことが説明されています。:-)
少し混乱するかもしれませんがjava.lang.Object.registerNatives、前の回答で示したコードは、ネイティブ関数を登録する方法の単なる例です。これは、(OpenJDK の実装で) クラス Object のネイティブ関数を登録するコードです。RegisterNatives独自のクラスにネイティブ関数を登録するには、独自のライブラリのネイティブ コードからJNI 関数を呼び出す必要があります。これは少し循環しているように聞こえるかもしれませんが、ループを断ち切る方法がいくつかあります。
クラス Object のこの実装の例に従います。
を。Java クラスで、ネイティブ メソッド (可能であれば静的) を宣言します
registerNatives(または他の名前。問題ありません)。b. ネイティブ コードで
Java_<your fully qualified class name>_registerNatives、JNI 関数 への呼び出しを含むという名前の関数を定義しますRegisterNatives。c.
registerNativesJava コードでは、Javaメソッドが他のネイティブ メソッドの呼び出しの前に呼び出されることを確認してください。
また
使用する
JNI_OnLoadを。ネイティブ ライブラリで関数を定義します
jint JNI_OnLoad(JavaVM *vm, void *reserved)。この関数の本体で、JNI 関数を呼び出しますRegisterNatives。b.
JNI_OnLoadネイティブ ライブラリが によってロードされると、 Java VM は自動的に検索して呼び出しますSystem.loadLibrary。これは、おそらくクラスの静的初期化子で既に呼び出しているはずです。(ポインターが指すテーブル内envの関数を呼び出すことによって、必要なポインターを取得します。)GetEnvvm