JNI 在 C 中调用不同,C++?

2022-09-01 09:50:01

所以我在C中有以下代码,它利用Java Native Interface,但是我想将其转换为C++但不确定如何。

 #include <jni.h>
 #include <stdio.h>
 #include "InstanceMethodCall.h"

 JNIEXPORT void JNICALL 
 Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
 {
     jclass cls = (*env)->GetObjectClass(env, obj);
     jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V");
     if (mid == NULL) {
         return; /* method not found */
     }
     printf("In C\n");
     (*env)->CallVoidMethod(env, obj, mid);
 }

Java 程序:

 class InstanceMethodCall {
     private native void nativeMethod();
     private void callback() {
         System.out.println("In Java");
     }
     public static void main(String args[]) {
         InstanceMethodCall c = new InstanceMethodCall();
         c.nativeMethod();
     }
     static {
         System.loadLibrary("InstanceMethodCall");
     }
 }

JNI与C和C++交互有什么区别?任何帮助都非常感谢。

谢谢,皮特


答案 1

我曾经有一本书Essential JNI。虽然它有点过时了,但其中大部分今天仍然有效。

如果我没记错的话,在C语言中,Java结构只是指针。因此,在您的代码中,“”是取消引用指针,以允许您访问基础方法。(*env)->

对于C++,“”实际上是一个对象 - 与C指针不同的实体。(JNI 实际上可以提供真实的对象供C++代码操作,因为C++实际上支持对象。所以“”在C++有不同的含义,它的意思是“调用”“所指向的对象中包含的方法。envenv->env

我相信,另一个区别是,许多C-JNI函数要求你的一个参数是“”。所以在C中,你可能不得不说.对于 c++,对 “” 的第二个引用不是必需的,因此您可以改为说”JNIEnv *env(*env)->foo(env, bar)envenv->foo(bar)"

不幸的是,我面前没有上面的书,所以我不能完全确认这一点!但我认为调查这两件事(特别是在谷歌或其他JNI代码中寻找它们)会让你走得更远。


答案 2

C 和 CPP 中的 JNI 调用之间的主要区别在于:

C-style JNI 看起来像 (*env)->SomeJNICall(env, param1 ...)

C++风格的JNI看起来像env->SomeJNICall(param1 ...)

因此,要将其转换为CPP,您需要做

Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj)
{
    jclass cls = env->GetObjectClass(obj);
    jmethodID mid = env->GetMethodID(cls, "callback", "()V");
    if (mid == NULL) {
        return; /* method not found */
}
printf("In C++\n");
env->CallVoidMethod(obj, mid);
//rest of your code

此外,请确保您的 JNI 函数遵循命名约定。

例:

JNIEXPORT jint JNICALL Java_com_shark_JNITestLib_JNITestLib_startServer(JNIEnv* env, jobject o, jstring inputName, jstring streamName, jstring description) {

您可以看到约定是Java_(包名)_(类名)_(方法名)

因为上面的那个在类中使用了,比如

package com.shark.JNITestLib

import java.util.stuff;

public class JNITestLib 
{
    static
    {
        System.loadLibrary("myJNIlib");
    }

    public native synchronized int startServer(String inputName, String streamName, String description);

//more class stuff...
}

在使用 JNI 时,我约定将包含 JNI 调用的类命名为与包同名。这就是为什么你看到JNITestLib两次(这就是为什么我的JNI马上工作,因为我总是忘记如何正确命名JNI调用)

干杯,希望我帮助:)


推荐