JNI开发,java层其实都是次要的,只管调用设计好的API就可以,最主要的角色,自然要属JNI层C++语言开发。由于JNI开发和Java可能是表亲戚的关系,所以JNI的一些语言特性,提供的API还是很类似于Java的,所以相对于纯C开发,其实我们java开发对JNI更容易上手。熟读JNI 提供的API 方法,助你开发如鱼得水
[h3]java调用C++方法[/h3]之前有说过,JNI层代码,是由Java每个native 方法映射过去的,
比如java 方法- final private native long CreateInstance(int logLevel,String logPath);
复制代码
- JNIEXPORT jlong JNICALL Java_com_hexin_tdsapi_AbstractTds_CreateInstance (JNIEnv *env, jobject ob,jint logLevel, jstring logPath)
复制代码 , 这里的方法名其实可以在头文件里 中 Copy过来,具体在方法体里实现自己需要的C代码。
JNIEXPORT jlong JNICALL Java_com_hexin_tdsapi_AbstractTds_CreateInstance (JNIEnv *env, jobject ob,jint logLevel, jstring logPath){ LOGD("im from static moethod C++ , value is : %d",logLevel);}=====================Java====================public class test { public static void main(String[] args) { TDS_TEST tds = new TDS_TEST(); tds.CreateInstance(100,""); }}
[h3]C++调用Java实例方法[/h3]是个简单的C的方法体
void callJavaInstanceMethod(JNIEnv *env, jobject instance) { jclass clazz = NULL; jmethodID method_id = NULL; jstring str_log = NULL; clazz = env->FindClass("com/hexin/demo/Hello"); if (clazz == NULL){ LOGD("没有发现该类"); return; } method_id = env->GetMethodID(clazz,"instanceMethod","(Ljava/lang/String;)V");// 方法签名 if (method_id == NULL){ LOGD("没有发现该方法名"); return; } str_log = env->NewStringUTF("c++ 调用java的实例方法"); env->CallVoidMethod(instance,method_id,str_log); //clazz 改为instance env->DeleteLocalRef(clazz); env->DeleteLocalRef(str_log); return ;}
首先定义了三个变量,然后使用env调用封装好的方法FindClass,传入类名全路径,在jvm中如果有加载这个类,那么就会返回我们的这个类。
接着是获取方法的id,使用env调用GetMethodID,第一个参数是方法所在的类,第二个是方法名,第三个是方法签名。
然后使用env调用CallVoidMethod,传入类和方法和参数,完成对java层方法的调用。
如果一开始都不是很清楚,等这些JNI方法入参规则,可以在JDK 目录下 找到文件,查找对应的方法名字和具体方法。
最后不要忘记删除引用,不然会发生内存泄漏
另外 这里要讲一下的就是: 方法签名
在学习c++调用java方法时需要了解的是方法签名,关于方法签名,我觉得只要关注这两个地方就行了:
- 什么是方法签名:方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。
- 为什么要用方法签名:c语言中没有方法重载这个概念,如果java中有两个方法:long test(int n, String str, int[] arr) ,long test(String str) 。那么没有方法签名来标注一下,编译器不就懵逼了嘛(ノ`Д)ノ。
方法签名规则:
Java类型签名类型booleanZbyteBcharClongJcharCfloatFdoubleDshortSintI类L全限定类名数组[全限定类名
上述中类的签名规则是:”L+全限定类名+;”三部分组成,其中全限定类名以”/”分隔,而不是用”.”或”_”分隔。
[h3]C++调用Java静态方法[/h3]和实例方法的区别就两个地方,一个是CallStaticVoidMethod,一个是GetStaticMethodID:
callJavaInstanceMethod(JNIEnv *env, jobject instance) { jclass clazz = NULL; jmethodID method_id = NULL; jstring str_log = NULL; clazz = env->FindClass("com/hexin/demo/Hello"); if (clazz == NULL){ LOGD("没有发现该类"); return; } method_id = env->GetMethodID(clazz,"instanceMethod","(Ljava/lang/String;)V"); if (method_id == NULL){ LOGD("没有发现该方法名"); return; } str_log = env->NewStringUTF("c++ 调用java的实例方法"); env->CallVoidMethod(instance,method_id,str_log); //clazz 改为instance env->DeleteLocalRef(clazz); env->DeleteLocalRef(str_log); return ;}
[h3]C++调用Java变量[/h3]首先在java类中定义一个变量:
public String name = "im is java";然后贴上jni代码,主要方法是GetFieldID,第一个参数传入变量所在类,第二个参数是变量名,第三个参数是签名类型:
void changeField(JNIEnv *env, jobject instance) { jclass clazz = env->GetObjectClass(instance); if (clazz == NULL){ return; } jfieldID jfieldID = env->GetFieldID(clazz,"name","Ljava/lang/String;"); if (jfieldID == NULL){ return; } jstring obj_str = (jstring) env->GetObjectField(instance,jfieldID); if (obj_str == NULL){ return; } char* c_str = (char*) env->GetStringUTFChars(obj_str,JNI_FALSE); const char new_char[40] = "changed from c"; //复制new_char的内容到c_str strcpy(c_str,new_char); jstring new_str = env->NewStringUTF(c_str); LOGD("%s",new_char); env->SetObjectField(instance,jfieldID,new_str); env->DeleteLocalRef(clazz); env->DeleteLocalRef(obj_str); env->DeleteLocalRef(new_str); return;}[h3]C++调用Java静态变量[/h3]同理,静态变量也没啥好讲的了,这里就贴一下代码:
void changeStaticField(JNIEnv *env, jclass type) { jclass clazz = env->FindClass("com/hexin/demo/Hello"); if (clazz == NULL){ return; } jfieldID jfieldID = env->GetStaticFieldID(clazz,"age","I"); if (jfieldID == NULL){ return; } int age = env->GetStaticIntField(clazz,jfieldID); LOGD("%d",age); jint change_int = 12; env->SetStaticIntField(clazz,jfieldID,change_int); env->DeleteLocalRef(clazz);}
[h2]总结[/h2]其实JNI开发,并不是纯C的开发,JNI很多API已经提供完全,我们开发需要做的就是用C语言去实现调用这些API,可能遇到复杂的业务,对这些需求C的基础要求会比较高。纵观整个开发,从Java方向转入C++,在内存处理和C的指针性操作会比较难上手些,其他语言通性其实差不多。
总之,C++的开发 对于Android开发还是有很大帮助的!
|
|