JNI系列入门之C语言与Java的双向通信(二)

JNI系列文章:
JNI系列之入门Hello JNI C(一)
JNI系列之入门Hello JNI C(二)
JNI系列入门之C语言与Java的双向通信(一)
JNI系列入门之C语言与Java的双向通信(二)
JNI系列入门之C语言中文字符串乱码问题


C层向Java层通信

  • C层访问Java层的方法
// java代码
/*
* 在C中调用次方法,获取登入的用户id
*/
private String getLoginUserId(){
    return "100010";
}
// c代码
// 3. 访问java方法
JNIEXPORT void JNICALL Java_com_jerry_jnitest_JniTest_accessMethod
(JNIEnv *env, jobject jobj) {
    // 获取jclass
    jclass cls = (*env)->GetObjectClass(env, jobj);
    // 获取调用方法的jmethodID
    jmethodID methodID = (*env)->GetMethodID(env, cls, "getLoginUserId", "()Ljava/lang/String;");
    // 调用获取登录用户id的方法 
    jint value = (*env)->CallIntMethod(env, jobj, methodID);
    printf("userId = %s\n", value);
}
  • C层访问Java层的静态方法
// java代码
// c中调用的java静态方法
/**
  * 获取文件的大小
  * @param pathName
  * @return 文件大小
  */
  public static long getFileSize(String pathName){
      return new File(pathName).length();
  }
// 创建和写入一个字符串到文件中,并返回文件大小
JNIEXPORT jlong JNICALL Java_com_jerry_jnitest_JniTest_createAndWriteFile
(JNIEnv *env, jobject jobj, jstring jstr_file_path) {
    // 写入的文件路径 jstring->c
    char *filename = (*env)->GetStringUTFChars(env, jstr_file_path, NULL);
    printf("filename: %s\n", filename);
    // 创建一个文件, "w"表示写入权限,文件存在则覆盖
    FILE *fp = fopen(filename, "w");
    char *text = "在C中创建一个文件并写入内容,并返回文件大小";
    // c的文件io函数,写入文件
    fputs(text, fp);
    // 关闭流
    fclose(fp);

    // 计算文件的长度,这里不用c的函数来计算,改用调用java的文件api的方式来计算
    // 获取getFileSize方法所在类的类类型
    jclass jcls = (*env)->GetObjectClass(env, jobj);
    // 获取方法的id
    jmethodID mid = (*env)->GetStaticMethodID(env, jcls, "getFileSize",
        "(Ljava/lang/String;)J");
    // 调用方法
    jlong file_size = (*env)->CallStaticLongMethod(env, jcls, mid, jstr_file_path);
    printf("file_size: %lld", file_size);

    // 释放filename
    (*env)->ReleaseStringUTFChars(env, jstr_file_path, filename);
    return file_size;
}

这里我通过C调用了java的文件计算api,因为java计算文件比较简单,直接File.length()就好了。当然也可以用c来实现获取文件的长度大小:

// 4. 获取文件大小
int filesize(FILE *fp) {
    int length = 0;
    if (fp == NULL) {
        return length;
    }
    // 将文件指针的位置,重新定位文件指针
    // 0是偏移量,SEEK_END表示文件的末尾位置
    fseek(fp, 0, SEEK_END);
    // 返回当前文件指针,相对于文件开头的位置偏移量,就是文件字节长度
    length = ftell(fp);
    printf("length = %d\n", length);
    return length;
}

小伙伴们肯定会有疑问,你这方法的签名,记不住啊,容易懵逼啊。没有关系,我们还可以用命令的方式生成:


生成java的方法签名

javap -s -p 类的完整名称,可以自动生成属性和方法签名。

  • C层访问Java层的构造方法,并创建Java对象返回
// 5. 访问java的构造方法
// 使用java.util.Date获得一个时间戳
JNIEXPORT jobject JNICALL Java_com_jerry_jnitest_JniTest_accessConstructor
(JNIEnv *env, jobject jobj) {
    // 获取jclass
    jclass cls = (*env)->FindClass(env, "java/util/Date");
    // 获取jmethodID, 构造方法的名字使用<init>
    jmethodID contructor_mid = (*env)->GetMethodID(env, cls, "<init>", "()V");
    // 调用构造方法,实例化一个Date对象
    jobject date_jobj = (*env)->NewObject(env, cls, contructor_mid);

    // 调用Date的getTime方法
    // 获取date的jclass
    jclass date_cls = (*env)->GetObjectClass(env, date_jobj);
    // 获取getTime的jmethodID
    jmethodID getTime_mid = (*env)->GetMethodID(env, date_cls, "getTime", "()J");
    // 调用getTime方法
    jlong timestamp_jlong = (*env)->CallLongMethod(env, date_jobj, getTime_mid);
    printf("timestamp = %lld\n", timestamp_jlong);
    return date_jobj;
}

构造方法比较特殊,在获取jmethodID的时候传入的方法名是固定的<init>。

  • java中传入数组
// 8. java传入一个数组进行排序后同步

// 比较两个数的大小
int compare(int *a, int *b) {
    return (*a) - (*b);
}

JNIEXPORT void JNICALL Java_com_jerry_jnitest_JniTest_inputSortArray
(JNIEnv *env, jobject jobj, jintArray jintArr) {
    // 获取数组中的元素jint*
    jint *int_arr = (*env)->GetIntArrayElements(env, jintArr, NULL);
    // 获取数组长度
    int length = (*env)->GetArrayLength(env, jintArr);
    // 利用快速排序法排列数组
    qsort(int_arr, length, sizeof(jint), compare);

    // 同步操作后的数组内存到java中
    // 最后一个参数mode的解释
    // 0:Java的数组更新同步,然后释放C/C++的数组内存
    // JNI_ABORT:Java的数组不会更新同步,但是释放C/C++的数组内存
    // JNI_COMMIT:Java的数组更新同步,不释放C/C++的数组内存(但是函数执行完了局部的变量还是会释放掉)
    (*env)->ReleaseIntArrayElements(env, jintArr, int_arr, 0);
}

ReleaseIntArrayElements这个函数很重要,只有调用了这个函数,C中操作的数组元素,才会同步到java,否则java中传入的数组打印后还是原来的。

  • C中生成一个数组返回给java
// 9. C中生成一个数组返回给java
JNIEXPORT jintArray JNICALL Java_com_jerry_jnitest_JniTest_outputArray
(JNIEnv *env, jobject jobj, jint len) {
    // 创建一个jintArray数组变量
    jintArray jint_Arr = (*env)->NewIntArray(env, len);
    // 将jintArray转换成c的jint*指针进行数组赋值
    jint *elements = (*env)->GetIntArrayElements(env, jint_Arr, NULL);
    int i = 0;
    for (; i < len; i++) {
        elements[i] = i;
    }
    // 将C中的创建修改的数组同步到Java中
    (*env)->ReleaseIntArrayElements(env, jint_Arr, elements, 0);
    return jint_Arr;
}

同样也要调用ReleaseIntArrayElements函数,去同步操作的数据,java获取的数组才会有值,同时释放掉C/C++的数组内存。


JNI系列文章:
JNI系列之入门Hello JNI C(一)
JNI系列之入门Hello JNI C(二)
JNI系列入门之C语言与Java的双向通信(一)
JNI系列入门之C语言与Java的双向通信(二)
JNI系列入门之C语言中文字符串乱码问题

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容