java中registerNatives()
Object类的私有静态方法有什么作用?
3 回答
其他答案在技术上是正确的,但对于没有 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 的书,其中谈到了这一点以及更多内容。:-)
可能有点令人困惑的是,上java.lang.Object.registerNatives
一个答案中显示的代码只是如何注册本机函数的示例。这是(在 OpenJDK 的实现中)为类 Object 注册本机函数的代码。要为您自己的类注册本机函数,您必须RegisterNatives
从您自己的库中的本机代码调用 JNI 函数。这听起来可能有点循环,但有几种方法可以打破循环。
遵循类 Object 的这个实现的例子:
一种。在您的 Java 类中,声明一个名为
registerNatives
(或任何其他名称。没关系)的本机方法(最好是静态的)。湾。在您的本机代码中,定义一个名为 的函数
Java_<your fully qualified class name>_registerNatives
,其中包含对 JNI 函数的调用RegisterNatives
。C。确保在您的 Java 代码中,您的 Java
registerNatives
方法在调用其他本机方法之前被调用。
或者
采用
JNI_OnLoad
一种。在您的本机库中定义一个函数
jint JNI_OnLoad(JavaVM *vm, void *reserved)
。在此函数的主体中,调用 JNI 函数RegisterNatives
。湾。
JNI_OnLoad
当您的本机库由 加载时,Java VM 将自动查找并调用System.loadLibrary
,您应该已经在调用它,可能在您的类的静态初始化程序中。(您可以env
通过调用指针指向GetEnv
的表中的函数来获得所需的指针vm
。)
它用于这样的场景:
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。