1.C++层调用Java:
在C++中调用Java方法是通过JNI提供的接口实现的。这种调用的过程涉及以下几个步骤:
- 获取
JNIEnv
指针:这是调用Java方法的核心接口。 - 定位Java类:通过JNI提供的方法,找到你要调用的方法所在的Java类。
- 获取方法ID:通过方法名和签名来获取Java方法的ID。
- 调用Java方法:使用获取的方法ID来调用相应的Java方法。
- 处理返回值:如果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;}
详细解析
- 获取Java类的引用:使用
FindClass
方法来查找Java类。类名需要使用完整的包名,且用斜杠/
分隔。 - 获取方法ID:- 使用
GetMethodID
来获取实例方法的ID。需要提供方法名和方法签名。- 使用GetStaticMethodID
来获取静态方法的ID。签名格式为(参数类型)返回类型
,例如(II)I
表示两个int
参数,返回一个int
。 - 创建Java类的实例:使用
AllocObject
创建一个Java对象实例。然后,使用CallVoidMethod
调用实例方法。 - 调用静态方法:直接使用
CallStaticIntMethod
调用静态方法,并传递参数。 - 处理返回值:静态方法
addNumbers
返回一个int
,所以C++代码中捕获并输出这个结果。
注意事项
- 确保正确处理异常。使用
ExceptionCheck
或ExceptionOccurred
来检查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++)代码中的方法进行绑定。与静态注册不同,动态注册不要求本地函数名称遵循特定的命名规则,允许你在代码中手动注册方法。这种方式提供了更大的灵活性,尤其是在处理大型项目或多模块项目时非常有用。
动态注册的工作流程
- 定义 Java
native
方法:在 Java 类中声明native
方法,但不需要关心 C/C++ 代码中的函数名称。 - 实现 JNI_OnLoad 函数:在加载本地库时,JVM 会调用
JNI_OnLoad
函数。在这个函数中,你可以注册需要与native
方法绑定的 C/C++ 函数。 - 使用
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;}
版权归原作者 泡泡茶壶Wending 所有, 如有侵权,请联系我们删除。