美文网首页
JNI开发:对象的引用

JNI开发:对象的引用

作者: slds | 来源:发表于2017-06-20 20:45 被阅读0次

在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中的类型 , 都需要在合适的环境使用 

相关文章

网友评论

      本文标题:JNI开发:对象的引用

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