JNI开发:对象的引用

在C的实现方法里面, 创建一个Java对象的几个步骤:

  • 第一,findClass找到需要创建对象的类(全类名)
  • 第二,得到构造方法的ID,构造方法名称,统一使用<init>
  • 第三,使用NewObject创建Java对象
    当创建了这个类的对象之后 , 我们就可以使用这个类里面所提供的方法了 , 那么我们就可以在C中使用Java中其他对象的方法了

数组的引用处理(主要是同步问题)
Java方法中,通过调用accessField,利用C修改静态属性

//数组处理
public native void sortArray(int array[]);

public static void main(String[] args) {

    JniTest test = new JniTest();
    int arr[] = { 3, 2, 4, 5, 1, 0 };
    //调用C的函数进行快速排序
    test.sortArray(arr);
    System.out.println(Arrays.toString(arr));

}

C代码如下:

int compare(const int * a, const int * b){
    return (*a) - (*b);
}

JNIEXPORT void JNICALL Java_com_test_JniTest_sortArray
(JNIEnv * env, jobject jobj, jintArray arr){

    //创建Java数组
    //(*env)->NewIntArray(env, len);

    //通过Java的数组,拿到C的数组的指针
    jint* c_arr = (*env)->GetIntArrayElements(env, arr, NULL);
    //获取Java数组的大小
    jsize len = (*env)->GetArrayLength(env, arr);
    //排序,其中compare是函数指针,用于比较大小,与Java类似
    qsort(c_arr, len, sizeof(jint), compare);

    //操作完之后需要同步C的数组到Java数组中
    (*env)->ReleaseIntArrayElements(env, arr, c_arr, 0);
}```

__注意:__
1、通过GetIntArrayElements拿到C类型的数组的指针,然后才能进行C数组的处理。
2、C拿到Java的数组进行操作或者修改以后,需要调用ReleaseIntArrayElements进行更新,这时候Java的数组也会同步更新过来。
这个方法的最后一个参数是模式:

0: Java数组进行更新,并且释放C/C++数组。
JNI_ABORT: Java数组不进行更新,但是释放C/C++数组。
JNI_COMMIT: Java数组进行更新,不释放C/C++数组(函数执行完,数组还是会释放)。```

引用的分级
在Java中引用也有强弱之分 , 使用new创建的对象就是强引用,也可以使用WeakReference将对象包装成一个弱引用对象 。在C中也不列外 , C中也有一套全局引用,局部引用,弱全局引用等等

一 , 局部引用

// 局部引用
// 作用:C使用到或自行创建Java对象,需要告知虚拟机在合适的时候回收对象

//局部引用,通过DeleteLocalRef手动释放对象
//1.访问一个很大的java对象,使用完之后,还要进行复杂的耗时操作
//2.创建了大量的局部引用,占用了太多的内存,而且这些局部引用跟后面的操作没有关联性

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

    // 找到类
    jclass dateClass = (*env)->FindClass(env, "java/util/Date");

    // 得到构造方法ID
    jmethodID dateConstructorId = (*env)->GetMethodID(env, dateClass, "<init>", "()V");

    // 创建Date对象
    jobject dateObject = (*env)->NewObject(env, dateClass, dateConstructorId);

    // 创建一个局部引用
    jobject dateLocalRef = (*env)->NewLocalRef(env, dateObject);

    // 省略N行代码

    // 不再使用对象 , 则通知GC回收对象
    (*env)->DeleteLocalRef(env, dateLocalRef);
    // 因为dateObject也是局部对象,可以直接回收dateObject对象
    //(*env)->DeleteLocalRef(env, dateObject);

}```

__全局引用__

// 全局引用
// 定义全局引用
//共享(可以跨多个线程),手动控制内存使用
jstring globalStr;

/创建全局引用/
JNIEXPORT void JNICALL Java_com_zeno_jni_HelloJNI_createGlobalRef
(JNIEnv *env, jobject jobj) {

jstring jStr = (*env)->NewStringUTF(env, "I want your love !");

// 创建一个全局引用
globalStr = (*env)->NewGlobalRef(env, jStr);

}

/使用全局引用/
JNIEXPORT jstring JNICALL Java_com_zeno_jni_HelloJNI_useGlobalRef
(JNIEnv *env, jobject jobj) {

return globalStr;

}

/释放全局引用/
JNIEXPORT void JNICALL Java_com_zeno_jni_HelloJNI_deleteGlobalRef
(JNIEnv *env, jobject jobj) {

// 释放全局引用
(*env)->DeleteGlobalRef(env, globalStr);

}

//弱全局引用
//节省内存,在内存不足时可以是释放所引用的对象
//可以引用一个不常用的对象,如果为NULL,临时创建
//创建:NewWeakGlobalRef,销毁:DeleteGlobalWeakRef

__引用缓存__

/变量缓存/
JNIEXPORT void JNICALL Java_com_zeno_jni_HelloJNI_variableCach
(JNIEnv *env, jobject jobj) {

// 找到String类
jclass stringClass = (*env)->FindClass(env, "java/lang/String");

// 得到构造方法ID
jmethodID stringConstructorID = (*env)->GetMethodID(env, stringClass, "<init>", "()V");

// 创建String类
//// 缓存局部变量 , 只创建一次 , 关键字static
static jobject stringObject = NULL;
if (stringObject == NULL)
{
    stringObject = (*env)->NewObject(env, stringClass, stringConstructorID);

    printf("------------- create String object --------------\n");
}

/*jobject stringObject = (*env)->NewObject(env, stringClass, stringConstructorID);

printf("------------- create String object --------------\n");*/

}```
引用的分级 ,上述代码都有比较详细的注释 ,这里就不多加解释了 , 说一下全局引用的简单使用场景。
在开发中 , 我们常常需要初始化一些变量 , 进行全局使用 , 这里我们的全局引用就发挥了作用了 。

// 初始化全局变量
//初始化全局变量,动态库加载完成之后,立刻缓存起来
jstring initGlobalStr;

JNIEXPORT void JNICALL Java_com_zeno_jni_HelloJNI_initVariable
(JNIEnv *env, jclass jcls) {

    jstring initStr = (*env)->NewStringUTF(env, "create global init variable ");

    initGlobalStr = (*env)->NewGlobalRef(env, initStr);
}

/*访问初始化全局变量*/
JNIEXPORT jstring JNICALL Java_com_zeno_jni_HelloJNI_accessInitGlobalVariable
(JNIEnv *env, jobject jobj) {

    return initGlobalStr;
}


__java code__ 

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,599评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,581评论 18 399
  • 头很重,脚很轻。 楼道没有光, 暗色刚好覆盖影子。 滴答滴答的酒瓶, 杂乱的发, 嘶哑的嗓子, 半只手捂住了正在流...
    愚歌阅读 146评论 0 0
  • 集团年会彩排,也是一天,不过呢,珍惜这些日子,过好每一天,让自己变得更加努力吧! 阿猫开始上课了,好好学习,一起加油!
    聂一一阅读 148评论 0 0
  • 清早不再有赖床的习惯, 即便黑夜与白昼从不与孤独走散, 我也不想在沉睡里,寂寞给自己看。 昨晚打开的罐装可乐,沉默...
    笑容面具阅读 218评论 17 8