78

java中registerNatives()Object类的私有静态方法有什么作用?

4

3 回答 3

121

其他答案在技术上是正确的,但对于没有 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 函数如表中所列,这比编写一堆转发函数更方便。

如果您将 Java 嵌入到 C 程序中并希望链接到应用程序本身(而不是共享库中)的函数,或者正在使用的函数没有以其他方式“导出”,那么注册本机函数也很有用,因为这些标准方法查找机制通常不会找到。注册本机函数也可用于将本机方法“重新绑定”到另一个 C 函数(例如,如果您的程序支持动态加载和卸载模块,则很有用)。

我鼓励大家阅读JNI 的书,其中谈到了这一点以及更多内容。:-)

于 2009-06-18T12:40:19.183 回答
11

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

  1. 遵循类 Object 的这个实现的例子:

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

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

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

或者

  1. 采用JNI_OnLoad

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

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

于 2012-11-07T00:09:28.663 回答
0

它用于这样的场景:

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

当java代码需要调用host的C函数时,如果仍然使用jni dll( System.loadLibrary("foo.dll");)绑定native java方法,dll的内存空间和C host的内存空间是不一样的。(如果您调用的函数与主机状态无关,它仍然有效,但您无法以这种方式访问​​主机的状态值)

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

于 2021-09-21T03:23:50.377 回答