c++如何通过JNI与Java代码交互_c++与Java跨语言通信实现方法

通过JNI实现C++与Java双向通信,Java使用native方法声明并由C++实现对应函数,C++通过JNIEnv指针调用Java方法回调,需管理类型转换、内存释放及全局引用,确保跨平台交互稳定。

在跨平台开发中,C++与Java之间的通信是一个常见需求。通过JNI(Java Native Interface),可以实现Java调用C++代码,也可以让C++触发Java方法回调。这种方式广泛应用于Android NDK开发、高性能计算模块集成等场景。

JNI基本原理

JNI是Java提供的标准接口,允许Java代码与本地语言(如C/C++)交互。核心机制是:Java通过native关键字声明方法,由C++实现对应函数,并通过特定命名规则和JNI环境指针进行绑定。

JNIEnv* 是关键参数,它提供了操作Java对象、调用方法、访问字段的能力。所有与Java交互的操作都必须通过JNIEnv指针完成。

Java调用C++函数

实现步骤如下:

  • 在Java类中声明native方法:
    public native int add(int a, int b);
  • 使用javac编译后,用javah生成头文件(或使用javac -h),得到类似:
    Java_com_example_MathUtil_add(JNIEnv*, jobject, jint, jint);
  • C++中实现该函数,例如:

extern "C" JNIEXPORT jint JNICALL
Java_com_example_MathUtil_add(JNIEnv* env, jobject thiz, jint a, jint b) {
  return a + b;
}

注意extern "C"防止C++名称修饰,确保符号正确导出。

C++调用Java方法(回调)

当需要从C++主动通知Java时,需缓存类引用和方法ID:

  • 获取JavaVM指针(可在onLoad中保存)
  • 通过AttachCurrentThread获得当前线程的JNIEnv*
  • 查找目标类并获取jclass引用
  • GetMethodID或GetStaticMethodID获取方法句柄
  • 构造参数并调用CallVoidMethod等函数

示例代码片段:

JNIEnv* env;
JavaVM* jvm;
jvm->AttachCurrentThread(&env, nullptr);
jclass cls = env->FindClass("com/example/Callback");
jmethodID mid = env->GetMethodID(cls, "onResult", "(I)V");
env->CallVoidMethod(obj, mid, 42);

数据类型转换与内存管理

JNI提供基本类型映射(如jint对应int),复杂类型需转换:

  • 字符串:NewStringUTF / GetStringUTFChars
  • 数组:GetIntArrayElements / ReleaseIntArrayElements
  • 对象创建:NewObject配合GetMethodID使用构造函数

务必成对使用获取与释放函数,避免内存泄漏或JVM崩溃。

全局引用可用于跨线程持有Java对象:
g_callback_obj = env->NewGlobalRef(obj);

基本上就这些。掌握JNI命名规则、环境获取、类型转换和生命周期管理,就能稳定实现C++与Java的双向通信。