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 .