2009-06-18 116 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指针。)