2009-06-18 123 views

回答

90

其他答案在技術上是正確的,但對於沒有JNI經驗的人不太有用。 :-)

通常,爲了讓JVM找到你的本地函數,它們必須以某種方式命名。例如對於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函數如表中所列,這比編寫一堆轉發函數更爲方便。

如果您在C程序中嵌入Java並希望鏈接到應用程序本身內的函數(而不是共享庫內),或者所使用的函數沒有以其他方式「導出」,則註冊本地函數也很有用「,因爲這些通常不會被標準方法查找機制發現。註冊本地函數也可用於將本地方法「重新綁定」到另一個C函數(例如,如果您的程序支持動態加載和卸載模塊,則可用)。

我鼓勵大家閱讀JNI book,這個會談這個以及更多。 :-)

-9

既然你看了源代碼找到它,這很容易猜到是不是?

這是一個本地方法,它被稱爲registerNatives,所以我猜它註冊了基礎平臺的對象。

它也是私人的,所以它可能沒有什麼值得關注的。

+20

你必須是一個封閉的程序員(「一步之遙,沒什麼可看的」),而不習慣人們真正想知道「底層」下發生了什麼的想法。說夠了。 :-P – 2009-06-18 16:42:45

+2

該死的,那是顯而易見的,不是嗎? – aberrant80 2009-06-19 03:41:01

8

可能有點混淆的是在前面的答案中顯示java.lang.Object.registerNatives的代碼只是示例如何註冊本地函數。這是(在OpenJDK的實現中)爲類Object註冊本機函數的代碼。要爲您自己的類註冊本機函數,您必須從您自己的庫中的本機代碼調用JNI函數RegisterNatives。這聽起來有點循環,但有幾種方法可以打破循環。

  1. 關注這個實現類對象的例子:

    一個。在您的Java類中,聲明名爲registerNatives(或任何其他名稱,無關緊要)的本地方法(最好是靜態方法)。

    b。在您的本機代碼中,定義一個名爲Java_<your fully qualified class name>_registerNatives的函數,其中包含對JNI函數RegisterNatives的調用。

    c。確保在您的Java代碼中,在調用其他本地方法之前調用Java registerNatives方法。

OR

  • 使用JNI_OnLoad

    一個。在你的本地庫中定義一個函數jint JNI_OnLoad(JavaVM *vm, void *reserved)。在這個函數的主體中,調用JNI函數RegisterNatives

    b。當您的本機庫被System.loadLibrary加載時,Java VM將自動查找並調用JNI_OnLoad,您應該已經調用了它,可能是在您的類的靜態初始化程序中。 (您可以通過調用函數GetEnv表中的vm指針指向獲得所需的env指針。)