美文网首页
JNI数据类型,C访问Java属性与方法访问

JNI数据类型,C访问Java属性与方法访问

作者: 潇洒人生_cca2 | 来源:发表于2020-04-05 10:31 被阅读0次

    每个native函数,都至少有两个参数(JNIEnv*,jclass或者jobject)
    1 当native方法为静态方法时:
    jclass 代表native方法所属类的class对象(JniTest.class)
    2 当native方法为非静态方法时:
    jobject 代表native方法所属的对象

    #define _CRT_SECURE_NO_WARNINGS
    #include "com_ccg_jni_JniTest.h"
    #include <string.h>
    
    //函数实现
    JNIEXPORT jstring JNICALL Java_com_ccg_jni_JniTest_getStringFromC
    (JNIEnv *env, jclass jcls){
        //JNIEnv 结构体指针
        //env二级指针
        //代表Java运行环境,调用Java中的代码
        //简单的实现
        //将C的字符串转为一个java字符串
        return (*env)->NewStringUTF(env,"C String");
    }
    
    JNIEXPORT jstring JNICALL Java_com_ccg_jni_JniTest_getStringFromCPP
    (JNIEnv *env, jclass jcls){
        //JNIEnv 在C++中就是一个结构体的别名
        //env 在C++中一个结构体的一级指针
        return env->NewStringUTF("CPP String");
    }
    

    基本数据类型

    Java基本数据类型与JNI数据类型的映射关系
    Java类型->JNI类型->C类型
    /*
    boolean jboolean
    byte jbyte;
    char jchar;
    short jshort;
    int jint;
    long jlong;
    float jfloat;
    double jdouble;
    void void
    */
    引用类型(对象)
    String jstring
    object jobject
    数组,基本数据类型的数组
    byte[] jByteArray
    对象数组
    object jobjectArray

    访问属性

    JNIEXPORT jstring JNICALL Java_com_ccg_jni_JniTest_accessField
    (JNIEnv *env, jobject jobj){
        //jobj是t对象,JniTest.class
        jclass cls = (*env)->GetObjectClass(env, jobj);
        //jfieldID
        //属性名称,属性签名
        jfieldID fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");   
    
        //jason >> super jason
        //获取key属性的值
        //Get<Type>Field
        jstring jstr = (*env)->GetObjectField(env, jobj, fid);  
        printf("jstr:%#x\n",&jstr);
    
        //jstring -> c字符串
        //isCopy 是否复制(true代表赋值,false不复制,也可以写NULL代表不复制)
        char *c_str = (*env)->GetStringUTFChars(env,jstr,JNI_FALSE);
        //拼接得到新的字符串
        char text[20] = "super ";
        strcat(text,c_str);
    
        //c字符串 ->jstring
        jstring new_jstr = (*env)->NewStringUTF(env, text);
    
        //修改key
        //Set<Type>Field
        (*env)->SetObjectField(env, jobj, fid, new_jstr);
    
        printf("new_jstr:%#x\n", &new_jstr);
    
        return new_jstr;
    }
    

    数据类型和签名的对应关系

    Java属性与方法签名列表.png

    访问静态属性

    JNIEXPORT void JNICALL Java_com_ccg_jni_JniTest_accessStaticField
    (JNIEnv *env, jobject jobj){
        //jclass
        jclass cls = (*env)->GetObjectClass(env, jobj);
        //jfieldID
        jfieldID fid = (*env)->GetStaticFieldID(env, cls, "count", "I");
        //GetStatic<Type>Field
        jint count = (*env)->GetStaticIntField(env, cls, fid);
        count++;
        //修改
        //SetStatic<Type>Field
        (*env)->SetStaticIntField(env,cls,fid,count);
    }
    

    访问java方法

    JNIEXPORT void JNICALL Java_com_ccg_jni_JniTest_accessMethod
    (JNIEnv *env, jobject jobj){
        //jclass
        jclass cls = (*env)->GetObjectClass(env, jobj);
        //jmethodID 查看方法签名,命令进入java.class目录,使用javap -s -p 完整类名 即可查看
        jmethodID mid = (*env)->GetMethodID(env, cls, "genRandomInt", "(I)I");
        //调用
        //Call<Type>Method
        jint random = (*env)->CallIntMethod(env, jobj, mid, 200);
        printf("random num:%ld",random);
    }
    

    静态方法

    JNIEXPORT void JNICALL Java_com_ccg_jni_JniTest_accessStaticMethod
    (JNIEnv *env, jobject jobj){
        //jclass
        jclass cls = (*env)->GetObjectClass(env, jobj);
        //jmethodID 
        jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getUUID", "()Ljava/lang/String;");
        
        //调用
        //CallStatic<Type>Method
        jstring uuid = (*env)->CallStaticObjectMethod(env, cls, mid);
    
        //随机文件名称 uuid.txt
        //jstring -> char*
        //isCopy JNI_FALSE,代表java和c操作的是同一个字符串
        char *uuid_str = (*env)->GetStringUTFChars(env, uuid, JNI_FALSE);
        //拼接
        char filename[100];
        sprintf(filename, "D://%s.txt",uuid_str);
        FILE *fp = fopen(filename,"w");
        fputs("i love jason", fp);
        fclose(fp);
    }
    

    访问构造方法

    //使用java.util.Date产生一个当前的时间戳
    JNIEXPORT jobject JNICALL Java_com_ccg_jni_JniTest_accessConstructor
    (JNIEnv *env, jobject jobj){
        jclass cls = (*env)->FindClass(env, "java/util/Date");
        //jmethodID 构造方法名称用<init>
        jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "<init>", "()V");
        //实例化一个Date对象
        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);
    
        printf("\ntime:%lld\n",time);
    
        return date_obj;
    }
    

    调用父类的方法

    JNIEXPORT void JNICALL Java_com_ccg_jni_JniTest_accessNonvirtualMethod
    (JNIEnv *env, jobject jobj){
        jclass cls = (*env)->GetObjectClass(env, jobj);
        //获取man属性(对象)
        jfieldID fid = (*env)->GetFieldID(env, cls, "human", "Lcom/ccg/jni/Human;");
        //获取
        jobject human_obj = (*env)->GetObjectField(env, jobj, fid);
    
        //执行sayHi方法
        jclass human_cls = (*env)->FindClass(env, "com/ccg/jni/Human"); //注意:传父类的名称
        jmethodID mid = (*env)->GetMethodID(env, human_cls, "sayHi", "()V");
    
        //执行
        //(*env)->CallObjectMethod(env, human_obj, mid);(调用子类的方法)
        //调用的父类的方法
        (*env)->CallNonvirtualObjectMethod(env, human_obj, human_cls, mid);
    }
    

    中文问题(重点)

    JNIEXPORT jstring JNICALL Java_com_ccg_jni_JniTest_chineseChars
    (JNIEnv *env, jobject jobj, jstring in){
        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);
    }
    

    传入数组排序

    JNIEXPORT void JNICALL Java_com_ccg_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);
    }
    

    返回数组

    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;
    }
    

    相关文章

      网友评论

          本文标题:JNI数据类型,C访问Java属性与方法访问

          本文链接:https://www.haomeiwen.com/subject/hjijlctx.html