欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > JNI C++和JAVA交互

JNI C++和JAVA交互

2025/2/23 0:58:47 来源:https://blog.csdn.net/u012861978/article/details/141143185  浏览:    关键词:JNI C++和JAVA交互

1.C++层调用Java:

在C++中调用Java方法是通过JNI提供的接口实现的。这种调用的过程涉及以下几个步骤:

  1. 获取JNIEnv指针:这是调用Java方法的核心接口。
  2. 定位Java类:通过JNI提供的方法,找到你要调用的方法所在的Java类。
  3. 获取方法ID:通过方法名和签名来获取Java方法的ID。
  4. 调用Java方法:使用获取的方法ID来调用相应的Java方法。
  5. 处理返回值:如果Java方法有返回值,处理它。

下面是一个具体的例子,演示如何在C++中调用Java方法。

示例场景

假设我们有一个Java类 JavaClass,其中包含一个方法 sayHello 和一个静态方法 addNumbers

Java代码
package com.example;public class JavaClass {public void sayHello() {System.out.println("Hello from Java!");}public static int addNumbers(int a, int b) {return a + b;}
}

C++代码调用Java方法

在C++代码中,我们要调用JavaClass类的 sayHello 实例方法和 addNumbers 静态方法。

C++代码
#include <jni.h>
#include <iostream>// 一个例子函数,用于调用Java方法
void callJavaMethod(JNIEnv *env) {// 1. 获取Java类的引用jclass javaClass = env->FindClass("com/example/JavaClass");if (javaClass == nullptr) {std::cerr << "Failed to find Java class" << std::endl;return;}// 2. 调用实例方法 sayHello// 获取方法IDjmethodID sayHelloMethod = env->GetMethodID(javaClass, "sayHello", "()V");if (sayHelloMethod == nullptr) {std::cerr << "Failed to find method sayHello" << std::endl;return;}// 创建Java类的实例jobject javaObject = env->AllocObject(javaClass);if (javaObject == nullptr) {std::cerr << "Failed to create Java object" << std::endl;return;}// 调用实例方法env->CallVoidMethod(javaObject, sayHelloMethod);// 3. 调用静态方法 addNumbers// 获取静态方法IDjmethodID addNumbersMethod = env->GetStaticMethodID(javaClass, "addNumbers", "(II)I");if (addNumbersMethod == nullptr) {std::cerr << "Failed to find static method addNumbers" << std::endl;return;}// 调用静态方法jint result = env->CallStaticIntMethod(javaClass, addNumbersMethod, 3, 7);std::cout << "Result from Java addNumbers: " << result << std::endl;
}JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {JNIEnv *env;if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {return JNI_ERR;}// 在加载时调用Java方法callJavaMethod(env);return JNI_VERSION_1_6;
}

详细解析

  1. 获取Java类的引用:使用FindClass方法来查找Java类。类名需要使用完整的包名,且用斜杠/分隔。

  2. 获取方法ID

    • 使用GetMethodID来获取实例方法的ID。需要提供方法名和方法签名。
    • 使用GetStaticMethodID来获取静态方法的ID。签名格式为(参数类型)返回类型,例如(II)I表示两个int参数,返回一个int
  3. 创建Java类的实例:使用AllocObject创建一个Java对象实例。然后,使用CallVoidMethod调用实例方法。

  4. 调用静态方法:直接使用CallStaticIntMethod调用静态方法,并传递参数。

  5. 处理返回值:静态方法addNumbers返回一个int,所以C++代码中捕获并输出这个结果。

注意事项

  • 确保正确处理异常。使用ExceptionCheckExceptionOccurred来检查Java方法调用中是否出现异常。
  • 调用完成后释放资源,比如释放局部引用DeleteLocalRef

通过这些步骤,你可以在C++代码中灵活地调用Java方法,利用JNI在两个语言之间传递数据和功能。

2.java层调用C++层:

java层声明native函数,这个函数由Jni(C++)层实现,java层是如何通过native函数找到C++层的函数的?

需要把C++这些函数要注册到jni中,jni方法注册分为静态注册和动态注册:

1. 静态注册

通过Java中的native方法与C/C++代码中的JNI函数名称相匹配来实现的。静态注册要求C++代码中的函数名称与Java类中的native方法按照一定的规则命名,并自动进行绑定。这就是“静态”的含义,不需要额外的注册代码。

静态注册有明显缺点的:

  • JNI层的函数名太长;
  • 声明Native方法的类需要用javah工具生成头文件;
  • 第一次调用Native方法需要建立关联,影响运行效率;

2.JNI 动态注册

JNI 动态注册是通过在运行时将 Java native 方法与本地(C/C++)代码中的方法进行绑定。与静态注册不同,动态注册不要求本地函数名称遵循特定的命名规则,允许你在代码中手动注册方法。这种方式提供了更大的灵活性,尤其是在处理大型项目或多模块项目时非常有用。

动态注册的工作流程

  1. 定义 Java native 方法:在 Java 类中声明 native 方法,但不需要关心 C/C++ 代码中的函数名称。

  2. 实现 JNI_OnLoad 函数:在加载本地库时,JVM 会调用 JNI_OnLoad 函数。在这个函数中,你可以注册需要与 native 方法绑定的 C/C++ 函数。

  3. 使用 RegisterNatives 函数注册本地方法:通过 RegisterNatives 函数将 Java 的 native 方法与对应的 C/C++ 函数进行绑定。

动态注册的例子

Java 代码:
package com.example;public class MyClass {static {System.loadLibrary("mylib"); // 加载本地库}// 声明两个native方法public native int addNumbers(int a, int b);public native String getGreeting(String name);public static void main(String[] args) {MyClass obj = new MyClass();int result = obj.addNumbers(5, 10);System.out.println("Result: " + result);String greeting = obj.getGreeting("John");System.out.println("Greeting: " + greeting);}
}
C/C++ 代码:
#include <jni.h>
#include <string.h>// 实现两个本地方法
jint addNumbers(JNIEnv *env, jobject obj, jint a, jint b) {return a + b;
}jstring getGreeting(JNIEnv *env, jobject obj, jstring name) {const char *nameStr = (*env)->GetStringUTFChars(env, name, 0);char greeting[100];sprintf(greeting, "Hello, %s!", nameStr);(*env)->ReleaseStringUTFChars(env, name, nameStr);return (*env)->NewStringUTF(env, greeting);
}// 定义方法数组,将Java方法名和C函数进行绑定
static JNINativeMethod methods[] = {{"addNumbers", "(II)I", (void *)addNumbers},{"getGreeting", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getGreeting}
};// 在JNI_OnLoad中注册这些本地方法
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {JNIEnv *env;if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) != JNI_OK) {return JNI_ERR;}// 获取Java类jclass cls = (*env)->FindClass(env, "com/example/MyClass");if (cls == NULL) {return JNI_ERR;}// 注册本地方法if ((*env)->RegisterNatives(env, cls, methods, sizeof(methods) / sizeof(methods[0])) < 0) {return JNI_ERR;}return JNI_VERSION_1_6;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com