How to use JNI’s RegisterNatives() method? – 如何使用JNI’的RegisterNatives()方法?

最后修改: 2022年 2月 19日

1. Overview


In this short tutorial, we’ll take a look at the JNI RegisterNatives() method, which is used to create mappings between Java and C++ functions.

在这个简短的教程中,我们将看看JNI RegisterNatives()方法,它被用来在Java和C++函数之间创建映射。

First, we’ll explain how JNI RegisterNatives() works. Then, we’ll show how it’s used in the java.lang.Object’registerNatives() method. Finally, we’ll show how to use that functionality in our own Java and C++ code.

首先,我们将解释JNI的RegisterNatives()如何工作java.lang.ObjectsregisterNatives()方法中的应用。最后,我们将展示如何在我们自己的 Java 和 C++ 代码中使用该功能。

2. JNI RegisterNatives Method

2.JNI RegisterNatives方法

The JVM has two ways to find and link native methods with Java code. The first one is to call a native function in a specific way so that the JVM can find it. Another way is to use the JNI RegisterNatives() method.


As the name suggests, RegisterNatives() registers native methods with the class passed as an argument. By using this approach, we can name our C++ functions whatever we want.

顾名思义,RegisterNatives() 用作为参数传递的类来注册本地方法。通过使用这种方法,我们可以随心所欲地命名我们的C++函数

In fact, java.lang.Object’registerNatives() method uses the second approach. Let’s see a java.lang.Object’registerNatives() method implementation from OpenJDK 8 in C:

事实上,java.lang.Object’s registerNatives()方法采用的是第二种方法。让我们看看java.lang.Object’s registerNatives()方法在OpenJDK 8中的C语言实现。

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},

Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
    (*env)->RegisterNatives(env, cls,
                            methods, sizeof(methods)/sizeof(methods[0]));

Firstly, the method[] array is initialized to store mappings between Java and C++ function names. Then, we see a method named in a very specific way, Java_java_lang_Object_registerNatives.

首先, method[]数组被初始化以存储Java和C++函数名称之间的映射。然后,我们看到一个以非常特殊方式命名的方法,Java_java_lang_Object_registerNatives

By doing so, the JVM is able to link it to a native java.lang.Object’registerNatives() method. Inside it, the method[] array is used in the  RegisterNatives() method call.

通过这样做,JVM能够将其与本地的java.lang.Objects RegisterNatives()方法联系起来。在它里面,method[]数组被用于RegisterNatives()方法的调用中。

Now, let’s see how can we use it in our own code.


3. Using the RegisterNatives Method


Let’s start with the Java class:


public class RegisterNativesHelloWorldJNI {

    public native void register();
    public native String sayHello();

    public static void main(String[] args) {
        RegisterNativesHelloWorldJNI helloWorldJNI = new RegisterNativesHelloWorldJNI();

We define two native methods, register() and sayHello(). The former will use the RegisterNatives() method to register a custom C++ function to use when the native sayHello() method is called.


Let’s see the C++ implementation of Java’s register() native method:


static JNINativeMethod methods[] = {
  {"sayHello", "()Ljava/lang/String;", (void*) &hello },

JNIEXPORT void JNICALL Java_com_baeldung_jni_RegisterNativesHelloWorldJNI_register (JNIEnv* env, jobject thsObject) {
    jclass clazz = env->FindClass("com/baeldung/jni/RegisterNativesHelloWorldJNI");

    (env)->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(methods[0]));

Similarly to the java.lang.Object example, we first create an array to hold mappings between Java and C++ methods.


Then, we see a function called with a fully qualified Java_com_baeldung_jni_RegisterNativesHelloWorldJNI_register name. Unfortunately, it must be called this way in order for the JVM to find and link it with Java code. 


The function does two things. First, it finds the desired Java class. Then, it calls the RegisterNatives() method and passes it the class and the mappings array.


Now, we can call the second native method, sayHello(), whatever we want:


JNIEXPORT jstring JNICALL hello (JNIEnv* env, jobject thisObject) {
    std::string hello = "Hello from registered native C++ !!";
    std::cout << hello << std::endl;
    return env->NewStringUTF(hello.c_str());

Instead of the fully qualified name, we used a shorter, meaningful name.


Finally, let’s run the main() method from the RegisterNativesHelloWorldJNI class:


Hello from registered native C++ !!

4. Conclusion


In this article, we discussed the JNI RegisterNatives() method. Firstly, we explained what the java.lang.Object.registerNatives() method does under the hood. Then, we discussed why using the JNI RegisterNatives() method might be useful. Finally, we showed how to use it in our own Java and C++ code.

在这篇文章中,我们讨论了JNI的RegisterNatives()方法。首先,我们解释了java.lang.Object.registerNatives()方法在幕后的作用。然后,我们讨论了为什么使用JNI的RegisterNatives()方法可能是有用的。最后,我们展示了如何在我们自己的 Java 和 C++ 代码中使用它。

As always, the complete source code of the article is available over on GitHub.