1. 概要

この短いチュートリアルでは、 JNI RegisterNatives()メソッドを見ていきます。このメソッドは、Java関数とC++関数の間のマッピングを作成するために使用されます。

まず、JNIがどのように機能するかを説明します RegisterNatives() 作品次に、それがでどのように使用されるかを示します java .lang.Object ‘ s registerNatives() 方法。 最後に、独自のJavaおよびC++コードでその機能を使用する方法を示します。

2. JNI RegisterNativesメソッド

JVMには、ネイティブメソッドを見つけてJavaコードにリンクする2つの方法があります。 1つ目は、特定の方法でネイティブ関数を呼び出し、JVMがそれを見つけられるようにすることです。 もう1つの方法は、 JNI RegisterNatives()メソッドを使用することです。

名前が示すように、 RegisterNatives()は、引数として渡されたクラスにネイティブメソッドを登録します。 このアプローチを使用することで、C++関数に任意の名前を付けることができます

実際、 java .lang.Object’ s registerNatives()メソッドは2番目のアプローチを使用します。 CのOpenJDK8からのjava.lang.Object’ s registerNatives()メソッドの実装を見てみましょう。

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]));
}

まず、 method [] 配列が初期化され、JavaとC++の関数名間のマッピングが格納されます。 次に、非常に特殊な方法で名前が付けられたメソッドJava_java_lang_Object_registerNativesが表示されます。

そうすることで、JVMはそれをネイティブの java .lang.Object’ s registerNatives()メソッドにリンクできます。 その中で、 method []配列がRegisterNatives()メソッド呼び出しで使用されます。

それでは、独自のコードでどのように使用できるかを見てみましょう。

3. RegisterNativesメソッドの使用

Javaクラスから始めましょう:

public class RegisterNativesHelloWorldJNI {

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

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

2つのネイティブメソッドを定義します。 登録()こんにちはと言う()。 前者はRを使用します egisterNatives() ネイティブの場合に使用するカスタムC++関数を登録するメソッドこんにちはと言う() メソッドが呼び出されます。

Javaのregister()ネイティブメソッドのC++実装を見てみましょう。

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]));
}

java.lang.Object の例と同様に、最初にJavaメソッドとC++メソッド間のマッピングを保持する配列を作成します。

それで、 完全修飾されたJava_com_baeldung_jni_RegisterNativesHelloWorldJNI_register名で呼び出された関数が表示されます。 残念ながら、JVMがJavaコードを見つけてJavaコードにリンクするには、この方法で呼び出す必要があります。 

この関数は2つのことを行います。 まず、目的のJavaクラスを見つけます。 次に、 RegisterNatives()メソッドを呼び出し、クラスとマッピング配列を渡します。

これで、2番目のネイティブメソッド sayHello()を好きなように呼び出すことができます。

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());
}

完全修飾名の代わりに、短くて意味のある名前を使用しました。

最後に、 RegisterNativesHelloWorldJNIクラスからmain()メソッドを実行してみましょう。

Hello from registered native C++ !!

4. 結論

この記事では、JNI RegisterNatives()メソッドについて説明しました。。 最初に、 java.lang.Object.registerNatives()メソッドが内部で何をするかを説明しました。 次に、JNI RegisterNatives()メソッドの使用が役立つ理由について説明しました。 最後に、独自のJavaおよびC++コードでそれを使用する方法を示しました。

いつものように、記事の完全なソースコードは、GitHubから入手できます。