jni的常用方法和案例
JNI数据类型
Java基本数据类型与JNI数据类型的映射关系
JavaL类型->JNI类型->C类型
基本数据类型
jni |
java |
jboolean |
boolean |
jbyte |
byte |
jchar |
char |
jshort |
short |
jint |
int |
jlong |
long |
jfloat |
float |
jdouble |
double |
void |
void |
引用数据类型
String jstring
object jobject
基本数据类型数组
byte[] jByteArray
对象数组
object jobjectArray
C/C++访问Java的成员
案例:1.Java类中有个成员变量;2.main方法得到jni一个对象,然后调用对象中的方法;3.这个jni的方法需要得到Java类中的成员变量;4.jni中第二个参数依据方法是静态还是非静态,静态就是jclass,非静态是jobject,如果是jobject,操作如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| jcalss cls = (*env)->GetObjectClass(env,jobj); // 第三个参数是属性名,第四个参数是属性签名;拿到属性id jfieldID fid = (*env)->GetFieldID(env,cls,"key","Ljava/lang/String;"); // 获取到key属性的值 jstring jstr = (*env)->GetObjectField(env,jobj,fid); // 如果需要修改jstr 需要将jstr转为c字符串 // isCopy:第三个参数,三种:JNI_TRUE,JNI_FALSE,NULL,true代表复制,false代表不复制 char* c_str = (*env)->GetStringUTFChars(env,jstr,NULL); // c方法拼接 char text[20] = "new"; strcat(text, c_str); // c传jni字符串 (*env)-> new_jstr = (*evn)->newStringUTF(env,text); // 修改key (*env)->SetObjectField(evn,jobj,fid,new_jstr); return new_jstr;
|
访问静态属性,操作如下:
1 2 3 4 5 6
| jcalss cls = (*env)->GetObjectClass(env,jobj); jfieldID fid = (*env)->GetStaticFieldID(env,cls,"count","I"); jint cont = (*env)->GetStaticField(env,cls,fid); count ++; //修改 (*env)->SetStaticIntField(evn,jobj,fid,count);
|
访问Java方法
1 2 3
| public int getRandomInt(int max){ return new Random().nextInt(max); }
|
1 2 3 4
| jcalss cls = (*env)->GetObjectClass(env,jobj); jmethodId mid = (*env)->GetMethodID(env,cls,"getRandomInt","(I)I"); // 调用Call<Type>Method (*env)->CallIntMethod(env,jobj,mid,200);
|
javap -s -p com.xxx.xxx.abc可得到签名
访问Java静态方法
1 2 3
| public static String getUUID(){ return UUID().randomUUID().toString(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| jcalss cls = (*env)->GetObjectClass(env,jobj); jmethodID mid = (*env)->GetStaticMethodID(env,cls,"getUUID","签名"); // 调用 jstring uuid = (*env)->CallStaticObjectMethod(env,cls,mid); // 得到c字符串 char* uuid_str = (*env)->GetStringUTFChars(env,uuid,JNI_FALSE); // 拼接 char filename(100); printf(filename,"D://%s.txt,uuid_str); // 生成一个文件 FILE *fp = fopen(filename,"w"); fputs("i am jian",fp); fclose(fp);
|
访问构造方法
1 2 3 4 5 6 7 8 9
| jclass cls =(*env)->FindClass(env,"java/util/Date"); // jmethodID: jmethodID constructor_mid = (*env)->GetMethodID(env,cls,"<init>","()V"); // 实例化一个Data对象 jobject date_obj(*env)->NewObject(env,cls,constructor_mid); // 调用getTime方法 jmethodId mid = (*env)->GetMethodID(env,cls,"getTime","()J"); jlong time = (*env)->CallLongMethod(env,date_obj,mid); return date_obj
|
访问父类的方法
1 2 3 4 5 6 7 8 9 10 11 12
| jclass cls = (*env)->GetObjectClass(env,jobj); // 获取属性(对象) jfieldID fid = (*env)->GetFieldID(env,cls,"类名","签名"); // 获取 jobject _obj = (*env)->GetObject(env,jobj,fid); // 执行方法 jcalss x_cls = (*env)->FindClass(env,"com/xxx/xxx/xxx"); jmethode mid = (*env)->GetMethodID(env,x_cls,"方法","()V"); // 执行方法 (*env)->CallObjectMethod(env,x_obj,mid); // 执行父类方法,就是不覆盖父类方法 (*env)->CallNonvirtualObjectMethod(env,x_obj,cls,mid);
|
GetObjectClass和FindClass: FindClass是指定的,效率不高,类型java的getClass()和Class.forname();有对象用第一种,无对象用第二种
中文问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| JNIEXPORT jstring JNICALL Java_com_dongnaoedu_jni_JniTest_chineseChars (JNIEnv *env, jobject jobj, jstring in){ // 输出 //char *c_str = (*env)->GetStringUTFChars(env, in, JNI_FALSE); //printf("%s\n",c_str); // c -> jstring char *c_str = "马蓉与宋江"; // char c_str[] = "马蓉与宋喆"; //jstring jstr = (*env)->NewStringUTF(env, c_str); // 执行String(byte bytes[], String charsetName)构造方法需要的条件 // 1.jmethodID // 2.byte数组 // 3.字符编码jstring jclass str_cls = (*env)->FindClass(env, "java/lang/String"); jmethodID constructor_mid = (*env)->GetMethodID(env, str_cls, "<init>", "([BLjava/lang/String;)V"); // jbyte -> char // jbyteArray -> char[] jbyteArray bytes = (*env)->NewByteArray(env, strlen(c_str)); // byte数组赋值 // 0->strlen(c_str),从头到尾 // 对等于,从c_str这个字符数组,复制到bytes这个字符数组 (*env)->SetByteArrayRegion(env, bytes, 0, strlen(c_str), c_str); // 字符编码jstring jstring charsetName = (*env)->NewStringUTF(env, "GB2312"); // 调用构造函数,返回编码之后的jstring return (*env)->NewObject(env,str_cls,constructor_mid,bytes,charsetName); }
|
数组排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| int compare(int *a,int *b){ return (*a) - (*b); } //传入 JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_giveArray (JNIEnv *env, jobject jobj, jintArray arr){ //jintArray -> jint指针 -> c int 数组 jint *elems = (*env)->GetIntArrayElements(env, arr, NULL); //printf("%#x,%#x\n", &elems, &arr); //数组的长度 int len = (*env)->GetArrayLength(env, arr); //排序 qsort(elems, len, sizeof(jint), compare); //同步 //mode //0, Java数组进行更新,并且释放C/C++数组 //JNI_ABORT, Java数组不进行更新,但是释放C/C++数组 //JNI_COMMIT,Java数组进行更新,不释放C/C++数组(函数执行完,数组还是会释放) (*env)->ReleaseIntArrayElements(env, arr, elems, JNI_COMMIT); }
|
返回数组
1 2 3 4 5 6 7 8 9 10 11 12
| JNIEXPORT jintArray JNICALL Java_com_dongnaoedu_jni_JniTest_getArray(JNIEnv *env, jobject jobj, jint len){ // 创建一个指定大小的数组 jintArray jint_arr = (*env)->NewIntArray(env, len); jint *elems = (*env)->GetIntArrayElements(env, jint_arr, NULL); int i = 0; for (; i < len; i++){ elems[i] = i; } // 同步 (*env)->ReleaseIntArrayElements(env, jint_arr, elems, 0); return jint_arr; }
|