JNI 数组 异常处理 引用 缓存策略 方法访问 字符串乱码

java代码

public class JniTestModle {
    public String keys = "keyy";

    public native int accessMethod();

    public native int accessStaticMethod();

    public native String accessStaticMethodString();

    public native Date accessConstractor();

    public native String chineessChars(String str);

    public native String chineessCharsString(String str);

    public native void giveArray(int[] arr);

    public native String[] initStringArray(int size);

    public native void localref();

    public native void createGolbalRef();

    public native String getGolbalRef();

    public native void delGolbalRef();

    public native void exception();

    public native void cached();

    public native static void cachedGlobal();

    static {
        System.loadLibrary("JNI_C2_C7");
    }

    public static void main(String[] args) {
        JniTestModle jt = new JniTestModle();
        jt.accessMethod();
        System.out.println(jt.accessMethod());
        System.out.println(jt.accessStaticMethod());
        System.out.println(jt.accessStaticMethodString());
        System.out.println(jt.accessConstractor() + "......");
        System.out.println(jt.chineessChars("宝宝"));
        System.out.println(jt.chineessCharsString("宝宝"));
        int[] arr = { 12, 45, 65, 87, 1, 2, 54 };
        jt.giveArray(arr);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + ",");
        }
        String[] str = jt.initStringArray(2);
        for (int i = 0; i < str.length; i++) {
            System.out.print(str[i]);
        }
        jt.localref();

        jt.createGolbalRef();
        System.out.println(jt.getGolbalRef());
        jt.delGolbalRef();
        try {
            jt.exception();
        } catch (Exception e) {
            // TODO: handle exception
            // IllegalArgumentException
            System.out.println(e.toString());
        }
        System.out.println("................");
        jt.cached();
        jt.cachedGlobal();

    }

    int getRandomInt(int max) {
        return new Random().nextInt(max);
    }

    static int accessStaticInt(int max) {
        return new Random().nextInt(max);
    }

    static String accessStaticString() {
        String str = UUID.randomUUID().toString();
        return str;
    }
}
C代码

#include "stdafx.h"
#include "jnitest_JniTestModle.h"
#include <Windows.h>
#include <string.h>

JNIEXPORT jint JNICALL Java_jnitest_JniTestModle_accessMethod
(JNIEnv * env, jobject jobj){
    int a = 0;
    //jclass
    jclass jclz = (*env)->GetObjectClass(env, jobj);
    //jmethId  方法名字,方法签名
    jmethodID mid = (*env)->GetMethodID(env, jclz, "getRandomInt", "(I)I");
    //调用
    a = (*env)->CallIntMethod(env, jobj, mid, 2000);

    return a;
};
//访问静态方法 int  基本数据类型
JNIEXPORT jint JNICALL Java_jnitest_JniTestModle_accessStaticMethod
(JNIEnv *env, jobject jobj){
    int a = 0;
    //jclass
    jclass jclz = (*env)->GetObjectClass(env, jobj);
    //jmethId  方法名字,方法签名
    jmethodID mid = (*env)->GetStaticMethodID(env, jclz, "accessStaticInt", "(I)I");
    //调用
    a = (*env)->CallStaticIntMethod(env, jobj, mid, 2000);

    return a;
};

//访问静态方法 引用类型方法
JNIEXPORT jstring JNICALL Java_jnitest_JniTestModle_accessStaticMethodString
(JNIEnv *env, jobject jobj){
    //jclass
    //给了类的对象找class
    jclass jclz = (*env)->GetObjectClass(env, jobj);
    //jmethId  方法名字,方法签名
    jmethodID mid = (*env)->GetStaticMethodID(env, jclz, "accessStaticString", "()Ljava/lang/String;");
    //调用
    jstring jstr = (*env)->CallStaticObjectMethod(env, jobj, mid);
    printf("%s\n", jstr);
    char * c_str = (*env)->GetStringUTFChars(env, jstr, NULL);
    printf("%s\n", c_str);
    char fileName[100];
    sprintf(fileName, "D://%s.text", c_str);
    FILE *fp = fopen(fileName, "w");
    fputs("I  Love Me", fp);
    fclose(fp);
    printf("文件写入成功!\n");
    return jstr;
};

//访问构造方法   所有java中
JNIEXPORT jobject JNICALL Java_jnitest_JniTestModle_accessConstractor
(JNIEnv *env, jobject jobj)
{//jclass   给了类的名字让后根据名字找类
    jclass jclz = (*env)->FindClass(env, "java/util/Date");
    //所有构造方法都是传<init>
    jmethodID jmid = (*env)->GetMethodID(env, jclz, "<init>", "()V");
    //实例化  调用NewObject实例化Date对象,返回值是一个jobject
    //所有引用类型都转换成 jobject  
    //第三个参数 后面的构造器中传参一次传
    jobject date_obj = (*env)->NewObject(env, jclz, jmid);
    //jmethodID long 型 是J
    jmethodID time_id = (*env)->GetMethodID(env, jclz, "getTime", "()J");
    //返回值
    jlong time = (*env)->CallLongMethod(env, date_obj, time_id);
    printf("time : %lld\n", time);
    return date_obj;
};

//可以不定义,防止第三方调用,直接创建使用
//编码方式 java ;utf-16 16bit 2字节   JNI  utf-8英文1字节 中文3字节
//c/c++ ASCII编码 中文的编码方式GB2312 编码,中文2个字节 

//字符乱码1   (两种解决方式)
JNIEXPORT jstring JNICALL Java_jnitest_JniTestModle_chineessChars
(JNIEnv *env, jobject jobj, jstring str){
    jboolean iscrp;
    //传指针之后,获得参数结果
    char *c_str = (*env)->GetStringUTFChars(env, str, &iscrp);
    if (iscrp == JNI_TRUE){
        printf("is copy :JNI_TRUE \n");
    }
    else if (iscrp == JNI_FALSE){
        printf("is copy :JNI_FALSE \n");
    }

    int length = (*env)->GetStringLength(env, str, NULL);
    //jchar ->char
    const jchar * jcstr = (*env)->GetStringChars(env, str, NULL);
    if (jcstr == NULL){
        return NULL;
    }
    char *rtn = (char *)malloc(sizeof(char)*length * 2 + 3);
    memset(rtn, 0, sizeof(char)* 2 * length + 3);
    int size = 0;
    size = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)jcstr,
        length, rtn, sizeof(char)*length * 2 + 3, NULL, NULL);
    /*if (size <= 0){
        printf("%d\n", size);
        return NULL;
        }*/
    printf("rtn : %s\n", rtn);
    if (rtn != NULL){
        free(rtn);
        rtn = NULL;
    }
    if (iscrp == JNI_TRUE){
        //Jvm使用 ,通知JVM 可以释放 c_str 所指的空间可以释放了
        (*env)->ReleaseStringChars(env, str, c_str);
    }

    return str;
};

//字符乱码2

JNIEXPORT jstring JNICALL Java_jnitest_JniTestModle_chineessCharsString
(JNIEnv *env, jobject jobj, jstring str){
    char *c_str = "你说就是了abb";
    jclass str_cls = (*env)->FindClass(env, "java/lang/String");
    jmethodID jmid = (*env)->GetMethodID(env, str_cls, "<init>", "([BLjava/lang/String;)V");

    //jstring ->jbyteArray
    jbyteArray bytes = (*env)->NewByteArray(env, strlen(c_str));
    //将char *赋值到bytes
    (*env)->SetByteArrayRegion(env, bytes, 0, strlen(c_str), c_str);
    jstring charseName = (*env)->NewStringUTF(env, "GB2312");
    //直接使用构造器
    jstring strq = (*env)->NewObject(env, str_cls, jmid, bytes, charseName);
    return strq;
};

//访问数组  基本数据类型数组引用类型的数组
JNIEXPORT void JNICALL Java_jnitest_JniTestModle_giveArray
(JNIEnv *env, jobject jobj, jarray arr){
    int compare(jint *a, jint *b);
    //转换数组    
    jint *elemts = (*env)->GetIntArrayElements(env, arr, NULL);
    //系统提供的快速排序
    if (elemts == NULL){
        return NULL;
    }
    int len = (*env)->GetArrayLength(env, arr);
    qsort(elemts, len, sizeof(jint), compare);
    //释放可能的内存
    //将JNI 修改的数据重新写回原来的内存
    (*env)->ReleaseIntArrayElements(env, arr, elemts, JNI_COMMIT);
};

 

int compare(jint *a, jint *b){
    return *a - *b;
}
//访问引用类型的数据
JNIEXPORT jobjectArray JNICALL Java_jnitest_JniTestModle_initStringArray
(JNIEnv *env, jobject jobj, jint size){
    //创建
    jobjectArray result;
    jclass jclz;
    jclz = (*env)->FindClass(env, "java/lang/String");
    if (jclz == NULL){
        return NULL;
    }
    result = (*env)->NewObjectArray(env, size, jclz, jobj);
    if (result == NULL){
        return NULL;
    }

    //赋值
    int i;
    for (i = 0; i < size; i++)
    {
        //c字符串
        char *c_str = (char*)malloc(256);
        memset(c_str, 0, 256);
        //将int 转化成为char 
        sprintf(c_str, "hello num : %d\n", i);
        //c->jstring 
        jstring str = (*env)->NewStringUTF(env, c_str);
        if (str == NULL){
            return NULL;
        }
        //将就string 赋值给数组
        (*env)->SetObjectArrayElement(env, result, i, str);
        free(c_str);
        c_str = NULL;
    }
    //返回
    return result;
};

//JNI 引用
//局部引用   
//全局引用
//弱全局引用 
//局部引用 定义方式多样:Findclass NewObject ,GetObjectClass,NewCharArray....
//NewLocalRef()
//释放方式:方法调用完,JVM会自动释放
//         手动释放(局部引用表最多502个引用)
//局部引用不能再多线程中使用,只能在定义的地方使用
//全局引用 
//跨线程,夸方法使用
//局部引用
JNIEXPORT void  JNICALL Java_jnitest_JniTestModle_localref
(JNIEnv *env, jobject jobj){
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        jclass cls = (*env)->FindClass(env, "java/util/Date");
        jmethodID mid = (*env)->GetMethodID(env, cls, "<init>", "()V");
        //创建一个 Date 类型的局部引用
        jobject obj = (*env)->NewObject(env, cls, mid);
        //使用这个引用
        jmethodID time_id = (*env)->GetMethodID(env, cls, "getTime", "()J");
        //返回值
        jlong time = (*env)->CallLongMethod(env, obj, time_id);
        printf("localref : %lld\n", time);

        // 释放引用  局部引用表最多502个引用 不然那引用表溢出
        (*env)->DeleteLocalRef(env, obj);
        (*env)->DeleteLocalRef(env, cls);
    }

};
//全局引用  跨线程,跨方法
jstring global_str;
JNIEXPORT void  JNICALL Java_jnitest_JniTestModle_createGolbalRef
(JNIEnv *env, jobject jobj){

    jobject obj = (*env)->NewStringUTF(env, "JNI is intersting");
    //创建全局引用的唯一方法NewGlobalRef
    global_str = (*env)->NewGlobalRef(env, obj);
    printf("%s\n", global_str);

 

};

JNIEXPORT jstring  JNICALL Java_jnitest_JniTestModle_getGolbalRef
(JNIEnv *env, jobject jobj){

    return global_str;
};

JNIEXPORT void   JNICALL Java_jnitest_JniTestModle_delGolbalRef
(JNIEnv *env, jobject jobj){

    (*env)->DeleteGlobalRef(env, global_str);
};

//若全局引用
//他不会阻止GC 跨进程,跨方法
jclass g_weak_clz;
JNIEXPORT void   JNICALL Java_jnitest_JniTestModle_createlweakRef
(JNIEnv *env, jobject jobj){
    jclass jclz = (*env)->FindClass(env, "java/lang/String");
    g_weak_clz = (*env)->NewWeakGlobalRef(env, jclz);
};


//C语言中异常了 java就不能正常走下去了
//JNI 异常处理
//异常可以写一个工具类
JNIEXPORT void   JNICALL Java_jnitest_JniTestModle_exception
(JNIEnv *env, jobject jobj){
    jclass jclz = (*env)->GetObjectClass(env, jobj);
    jfieldID fid = (*env)->GetFieldID(env, jclz, "key", "Ljava/lang/String;");
    //检测是否发生异常
    jthrowable ex = (*env)->ExceptionOccurred(env);
    //判断异常是否发送
    if (ex != NULL)
    {
        jclass newExc;
        //清空JNI 产生的异常
        (*env)->ExceptionClear(env);
        //ILLegalArgumentException
        newExc = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
        if (newExc == NULL)
        {
            return NULL;
        }
        (*env)->ThrowNew(env, newExc, "Throw exception from JNI: GetFieldID faild");
    }
    printf("exception\n");
};

//缓存策略
JNIEXPORT void   JNICALL Java_jnitest_JniTestModle_cached
(JNIEnv *env, jobject jobj){
    jclass cls = (*env)->GetObjectClass(env, jobj);
    //静态局部变量 生命周期很长  存放在静态内存区
    //减少使用 Gc出现就出现野指针
    static jfieldID fid = NULL;
    if (fid == NULL)
    {
        fid = (*env)->GetFieldID(env, cls, "keys", "Ljava/lang/String;");
        printf("GetFieldID int \n");
    }
    printf("GetFieldID out \n");
};


//全局的静态变量  不要static  全局都能是使用
static jfieldID fid; //所有正在他定义行数之后 才起效果,在它定义的前面的方法访问不到
JNIEXPORT void   JNICALL Java_jnitest_JniTestModle_cachedGlobal
(JNIEnv *env, jobject obj){
    jclass jclz = (*env)->GetObjectClass(env, obj);
    if (fid == NULL)
    {
        fid = (*env)->GetFieldID(env, jclz, "keys", "Ljava/lang/String;");
        jstring str = (*env)->GetObjectField(env, obj, fid);
        printf("str : %s \n", str);
        printf("GetFieldIDStatic int \n");
    }
    printf("GetFieldIDStatic out  \n");
};

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值