RegisterNative()方法是做什么的?

在 java 中,Object 类的私有静态方法 registerNatives()做什么?

46788 次浏览

其他的答案在技术上是正确的,但对于没有 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 的书,其中谈到这一点和更多。 : -)

可能有点令人困惑的是,上一个答案中显示的 java.lang.Object.registerNatives代码只是一个关于如何注册本机函数的 例子。这是(在 OpenJDK 实现中)为 Object 类注册本机函数的代码。要为自己的类注册本机函数,必须从自己库中的本机代码调用 JNI 函数 RegisterNatives。这可能听起来有点循环,但是有一些方法可以打破循环。

  1. 按照 Object 类的这个实现的例子:

    在 Java 类中,声明一个名为 registerNatives的本机方法(最好是静态方法)(或任何其他名称。这无关紧要)。

    在本机代码中,定义一个名为 Java_<your fully qualified class name>_registerNatives的函数,它包含对 JNI 函数 RegisterNatives的调用。

    确保在 Java 代码中,在调用其他本机方法之前先调用 JavaregisterNatives方法。

或者

  1. 使用 JNI_OnLoad

    一。在本机库中定义一个函数 jint JNI_OnLoad(JavaVM *vm, void *reserved)。在这个函数体中,调用 JNI 函数 RegisterNatives

    B.当您的本机库由 System.loadLibrary加载时,Java VM 将自动查找并调用 JNI_OnLoad,您应该已经在类的静态初始化器中调用了 System.loadLibrary。(您可以通过调用 vm指针指向的表中的 GetEnv函数来获得所需的 env指针。)

在这样的场景中使用:

C 或 C + + 作为主机,Java 作为客户机。(C 加载 jvm.dll并使用 JNI_CreateJavaVM创建 JVM)

当 Java 代码需要调用 host 的 C 函数时, 如果仍然使用 jni dll (System.loadLibrary("foo.dll");)绑定本机 Java 方法,那么 dll 的内存空间与 C host 不同。(如果调用的函数是 东道国无关紧要,它仍然可以工作,但是不能以这种方式访问主机的状态值)

这里需要在主机上使用 env->RegisterNatives()将(绑定、公开、导出)主机的 C 函数注入到 JVM。