zoukankan      html  css  js  c++  java
  • JNI 学习笔记

    1、访问构造方法

    jclass cls = (*env)->FindClass(env,"java/util/Date");
    jmethodID constructor_mid = env->GetMethodID(env,cls,"<init>","()V");
    jobject date_obj = env->NewObject(env,cls,constructor_mid);
    <!-- 通知垃圾回收期回收对象 -->*env)->DeleteLocalRef(env,data_obj);

    2、访问父类的构造方法

    char* c_str = "迪丽热巴";
    jclass str_cls = (*env)->FindClass(env,"Ljava/langString;");
    jmethodID constructor_mid = (*env)->GetMethodID(env,str_cls,"<init>","([BLjava/lang/String;])V")
    <!-- 第一个参数 -->
    <!-- jbyte -> char -->
    jbyteArray bytes = (*env)->NewByteArray(env,strlen(c_str));
    <!-- byte 数组赋值 -->
    (*env)->SetByteArrayRegion(env,bytes,0,strlen(c_str),c_str);
    <!-- 第二个参数 -->
    jstring charsetName = (*env)->NewStringUTF(env,"GB2312");
    return (*env)->NewObject(env,str_cls,constructor_mid,bytes,charsetName);

    3、数组处理_JNI引用 数组排序 int[] arr

    1、函数指针:

    #include <stdlib.h>
    int compare(const void* a,const void* b){
    return (*a) -(*b);
    }
    
    <!-- 对java传递过来的数组进行排序 -->
    <!-- NULL 操作的是同一块内存 : 第三个参数是一个jboolean类型的指针,如果被赋值为1,表示内部进行了拷贝,为零表示内部没有拷贝,是同一块内存。程序员无法控制这个变量 -->
    jint * elems = (*eng)->GetIntArrayElements(env,arr,NULL);
    <!-- 数组的长度,env -->
    int len = (*eng)->GetArrayLength(env,arr);
    <!-- 函数指针 -->
    <!-- 排序 -->
    qsort(elems,len,sizeof(jint),compare);
    <!-- jni 数据同步 -->
    <!-- 第四个参数 mode
    0,java数组进行更新,并且释放C/C++数组
    JNI_ABORT,java 数组不进行更新,但是释放C/C++数组
    JNI_COMMIT,java数组进行更新,不释放C/C++数组(函数运行完,数组还是要释放的) -->
    (*env)->ReleaseIntArrayElements(env,arr,elems,0);

    2、返回一个int类型的数组

    jintArray jint_arr = (*env)->NewInntArray(env,len)
    jint* elems = (*env)->GetIntArrayElements(env,jint_arr,NULL);
    for(int i=0;i<len;++i){
    elems[i] = i;
    }
    (*env)->ReleaseIntArrayElements(env,jint_arr,elems,0);
    return jint_arr;

    3、局部引用和全局引用

    1、局部引用,通过DeleteLocalRef手动释放对象

    #1、访问一个很大的java对象,使用完之后,还要进行复杂的耗时操作
    #2、创建了大量的局部引用,占用了太多的内存,而且这些局部引用跟后面的操作没有关联。

    2、全局引用,多个方法里面都可以引用

    <!-- 解决数据共享问题(可以跨多个线程),手动控制内存的使用 -->
    <!-- 自己处理线程安全问题 -->

    jstring global_str;
    void createGlobalRef(){
      jstring obj = (*env)->NewStringUTF(env,"jni is powerful");
      global_str = (*env)->NewGlobalRef(obj);
    }
    
    void getGlobalRef(){
      return global_str;
    }
    
    void deleteGlobalRef(){
      (*env)->DeleteGlobalRef(global_str);
    }
    <!-- java 方法 -->
    class JniTest{
      public native void createGlobalRef();
      public native void getGlobalRef();
      public native void deleteGlobalRef();
      public static void main(String[] args){
        JniTest t = new JniTest();
        t.createGlobalRef();
        t.getGlobalRef();
        t.deleteGlobalRef();
        t.getGlobalRef();
      }
    }

    3、弱全局引用

    <!-- 节省内存,在内存不足时可以是释放所引用的对象 -->
    <!-- 可以引用一个不常用的对象,如果为NULL,临时创建 -->
    <!-- 创建: NewWeakGlobalRef,销毁 DeleteGlboalWeakRef -->

    4、异常处理 (Native 异常,无法在Java层catch) 只能在native 层处理

    <!--1、 保证java代码可以运行 -->
    <!--2、 确保补救措施,保证C代码继续运行-->
    <!--JNI 自己抛出的异常,在Java层无法被捕捉,只能在C层清空-->
    <!--用户自己抛出的异常,可以在Java层处理 -->
    void exception(JNIEnv* env,jobject obj){
      jclass cls = (*env)->GetObjectClass(env,obj);
      jfieldId fid = (*env)->GetFieldID(env,cls,"key2","Ljava/lang/String;");
      <!-- 检测是否发生Java异常 -->
      jthrowable exception = (*env)->ExceptionOccurred(env);
      if(exception != null){
        <!-- 让Java 代码可以继续执行 -->
        <!-- 清空异常信息 -->
        (*env)->ExceptionClear(env);
    
        <!-- 补救措施 -->
        <!-- 获取第二个属性 确保必须可以得到-->
        fid = (*env)->GetFieldID(env,cls,"key","Ljava/lang/String;");
      }
    
      jstring jstr = (*env)->GetObjectField(env,jobj,fid);
    
      char * str = (*env)->GetStringUTFChars(env,jstr,NULL);
    
      <!-- 对比属性值是否合法 -->
      if(stricmp(str,"super jason1") != 0){
        <!-- 认为抛出异常,给Java层处理 -->
        jclass newExeCls = (*env)->FindClass(env,"Ljava/lang/IllegalArgumentException;");
        (*env)->ThrowNew(env,newExeCls,"Key's value is invalid!");
      
      }
    }

    java 代码

    t.exception();

    4、缓存策略

    1、使用局部静态变量

    <!-- 在Java层循环调用很多次 一个native方法 -->
    void cached(JNIEnv* env,jobject obj){
        jclass cls = (*env)->GetObjectClass(env,obj);
    
        <!-- 获取fid 只获取一次 -->
        <!-- 局部静态变量 ; -->
        static jfieldID = key_id = null;
        if(key_id == null){
          key_id = (*env)->GetFieldID(env,cls,"key","Ljava/lang/String;");
          print("==========GetFieldID==========");
        }
    
    }        

    2、initIDs(),

    <!-- 在C层后面使用的对象在一个方法里面初始化,initIDs()在加载库的时候调用。 -->
    java

    public static void initIDs();
    static {
        System.load("lib");
        initIDs();
    }

    C :

    jfieldID key_fid;
    initIds(JNIEnv* env,jclass jcls){
        <!-- jclass cls = (*env)->GetObjectClass(env,obj); -->
        key_fid = (*env)->GetFieldID(env,jcls,"key","Ljava/lang/String;");
    }
  • 相关阅读:
    前端基础进阶变量对象详解
    伪元素::before与::after的用法
    网站性能优化你需知道的东西
    Python爬虫音频数据
    python一步高级编程
    Android APK打包流程
    软件漏洞学习
    pycrypto 安装
    ubuntu16.04中将python3设置为默认
    Android NDK 编译选项设置[zhuan]
  • 原文地址:https://www.cnblogs.com/roger-jc/p/11019261.html
Copyright © 2011-2022 走看看