0


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代码
packagecom.example;publicclassJavaClass{publicvoidsayHello(){System.out.println("Hello from Java!");}publicstaticintaddNumbers(int a,int b){return a + b;}}

C++代码调用Java方法

在C++代码中,我们要调用

JavaClass

类的

sayHello

实例方法和

addNumbers

静态方法。

C++代码
#include<jni.h>#include<iostream>// 一个例子函数,用于调用Java方法voidcallJavaMethod(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// 获取方法ID
    jmethodID 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// 获取静态方法ID
    jmethodID 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 代码:
packagecom.example;publicclassMyClass{static{System.loadLibrary("mylib");// 加载本地库}// 声明两个native方法publicnativeintaddNumbers(int a,int b);publicnativeStringgetGreeting(String name);publicstaticvoidmain(String[] args){MyClass obj =newMyClass();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){constchar*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;}

标签: c++ java 交互

本文转载自: https://blog.csdn.net/u012861978/article/details/141143185
版权归原作者 泡泡茶壶Wending 所有, 如有侵权,请联系我们删除。

“JNI C++和JAVA交互”的评论:

还没有评论