Перейти к основному содержимому

Как использовать метод RegisterNatives() JNI?

· 3 мин. чтения

1. Обзор

В этом кратком руководстве мы рассмотрим метод JNI RegisterNatives() , который используется для создания сопоставлений между функциями Java и C++.

Сначала мы объясним, как работает JNI RegisterNatives () . Затем мы покажем, как он используется в методе registerNatives() объекта java.lang.Object . Наконец, мы покажем, как использовать эту функциональность в нашем собственном коде Java и C++. ``

2. Метод JNI RegisterNatives

У JVM есть два способа найти и связать собственные методы с кодом Java. Первый — вызвать нативную функцию определенным образом , чтобы JVM могла ее найти. Другой способ — использовать метод JNI RegisterNatives() .

Как следует из названия, RegisterNatives() регистрирует собственные методы с классом, переданным в качестве аргумента. Используя этот подход, мы можем называть наши функции C++ как угодно .

На самом деле метод registerNatives() класса java.lang.Object использует второй подход. Давайте посмотрим на реализацию метода registerNatives() java.lang.Object из 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},
};

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 может связать его с методом registerNatives () нативного java.lang.Object . Внутри него массив 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();
}
}

Мы определяем два нативных метода: register() и sayHello(). Первый будет использовать метод RegisterNatives() для регистрации пользовательской функции C++, которая будет использоваться при вызове собственного метода sayHello() .

Давайте посмотрим на реализацию нативного метода Java register() на C++:

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


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

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

Как и в примере с java.lang.Object , мы сначала создаем массив для хранения сопоставлений между методами Java и C++.

Затем мы видим функцию, вызываемую с полным именем Java_com_foreach_jni_RegisterNativesHelloWorldJNI_register . К сожалению, он должен называться именно так, чтобы JVM могла его найти и связать с Java-кодом.

Функция делает две вещи. Во-первых, он находит нужный класс Java. Затем он вызывает метод RegisterNatives() и передает ему класс и массив сопоставлений.

Теперь мы можем вызывать второй нативный метод, 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());
}

Вместо полного имени мы использовали более короткое осмысленное имя.

Наконец, давайте запустим метод main() из класса RegisterNativesHelloWorldJNI :

Hello from registered native C++ !!

4. Вывод

В этой статье мы обсудили метод JNI RegisterNatives () . Во-первых, мы объяснили, что делает метод java.lang.Object.registerNatives() под капотом. Затем мы обсудили, почему использование метода JNI RegisterNatives() может быть полезным. Наконец, мы показали, как использовать его в нашем собственном коде на Java и C++.

Как всегда, полный исходный код статьи доступен на GitHub .