zoukankan      html  css  js  c++  java
  • JNI相关笔记 [TOC]

    JNI相关笔记

    1 生成native code所需要的头文件

    • 首先使用javac对java文件进行编译
    • 使用javah -jni [className],生成对应的头文件
    • 创建cpp文件,实现所需要的函数
    • 运行方式:java -Djava.library.path=. HelloWorld或者export LD_LIBRARY_PATH

    2 JNI提供的一些函数和方法

    • String对象的获取

      • 获取java传下来的String对象:const jbyte* byteString = (*env)->GetStringUTFChars(env,str,NULL);,由于该函数是对原来字符串的拷贝,所以使用完后需要对byteString进行NULL判断
        使用完毕后,需要释放获取的对象:(*env)->ReleaseStringUTFChars(env,str,byteString);

      • GetStringRegion/GetStringUTFRegion:会将字符串拷贝到预先申请的一片缓冲区里面(在栈上面,因此应避免大对象的拷贝),所以当使用这两个函数的时候,不需要进行NULL判断,也不需要进行Release操作

      • GetStringCritical/ReleaseStringCritical:会尽可能直接使用String的指针(也有可能返回字符串的拷贝),且该方法会阻塞垃圾回收,因此使用的时候需当做临界资源,即在这两个函数中间不能使用JNI调用或者阻塞

    • 类对象的获取

      • 获取当前类的实例:GetObjectClass:jclass cls = (*env)->GetObjectClass(env, obj)

        获取和设置类中成员变量的方法:

          jfieldID fid;		
          fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;");
          //cls为上一步获取的类的实例,GetStaticFieldID获取静态成员变量
          if(!fid) {
          	//需要判断是否获取成功
          	return; /* failed to find the field !*/
          }
          jstring str = (*env)->GetObjectField(env, obj, fid); //获取jstring对象,获取完后就可以转换为const char*类型来操作了
          jstring target = (*env)->NewStringUTF(env, "123");
          if(!jstr) {
              return; /*out of memory */
          } 
          (*env)->SetObjectField(env, obj, fid, jstr);  //设置对应的field
        

      调用java类中的方法:

          jclass cls = (*env)->GetObjectClass(env, obj); 
          jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V");
        	if(!mid) {
         		return; /* method not found */
       	}
        	printf("In C
      ");
          //直接调用java对象中的方法,对应的还有CallIntMethod, CallStaticVoidMethod, CallStaticBooleanMethod
      	(*env)->CallVoidMethod(env, obj, mid);  
      

    3 局部引用,全局引用,全局弱引用。

    局部应用的错误示例:https://www.kancloud.cn/owenoranba/jni/120497 以为用static变量来存储findClass的结果,实际上由于findClass返回的局部引用,该引用指向的对象可能已经被销毁,所以这样的做法是无用的
    正确的做法是用返回的局部引用创建一个GlobalRef:https://www.kancloud.cn/owenoranba/jni/120498

    一般来讲局部引用会自动进行释放,但是这种情况下,最好手动释放局部引用:

    for (int i = 0; i < len; ++i) {
      	jstring jstr = (*env)->GetObjectArrayElement(env, arr, i);
     	/* ... process jstr */
        (*env)->DeleteLocalRef(env, jstr);
    }
    

    IsSameObject(jobject obj1,jobject obj2):用来判断两个object是否引用的同一个对象,对于弱全局引用非常有效
    EnsureLocalCapacity(jint capacity):确保native函数在调用前有资源能够创建至少capacity个局部引用

    (*env)->PushLocalFrame(env, 10)和result = (*env)->PopLocalFrame(env, result):管理局部引用更高效的方式,示例:https://www.kancloud.cn/owenoranba/jni/120505

    4 异常

    当native代码调用java类中的方法的时候,有时候java类中可能会抛出异常,一般的检测方式为:

    (*env)->CallVoidMethod(env, obj, mid);
    //ExceptionCheck,更为高效的异常检查方式,返回值为boolean,只关心是否发生异常,不关心异常类的引用
    exc = (*env)->ExceptionOccurred(env);
    if(exc){
        jclass newExcCls;
        (*env)->ExceptionDescribe(env);
        //打印出异常的描述信息
        (*env)->ExceptionClear(env);//需要清理掉异常,为了下一次能够检测到
    	//省略部分代码
    }
    

    对于本地代码来讲,如果需要抛出异常,那么方式为:

    jclass newExcCls;
    newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); 
    if(!newExcCls){
        /*Unable to find the exception class, give up. */
        return;
    }
     
    (*env)->ThrowNew(env, newExcCls, "thrown from C code");   //抛出异常一个非常重要的一点,对于native代码来讲,ThrowNew方法并不会中断代码流程,所以需要手动去控制代码流程一个用于方便抛出异常的工具函数:
    void JNU_ThrowByName(JNIEnv *env, const char* name, const char* msg){
        jclass cls = (*env)->FindClass(env, name);
        /*if cls is NULL, an exception has already been thrown */
      	if(cls){
            (*env)->ThrowNew(env, cls, msg);
        }
      	/* free the local ref */
        (*env)->DeleteLocalRef(env, cls);//从此处也可以看出来,native代码中的ThrowNew是不影响流程的,需要自行控制
    }	
    
  • 相关阅读:
    nodejs 文件路径问题
    nodejs
    return , return true , return false的区别
    严防个人极端案事件 中央政法委要求健全危机干预机制
    《资本论》:什么是“原始积累”?农民的土地因何被社会剥夺
    程序员自我修炼(四)—— 代码重构
    中国各民族人口总数排名
    农村人可以去别的村买宅基地吗?这样合不合法?看完你就知道了!
    如果所在的农村拆迁了,可以在另外一个村申请宅基地吗?
    哈姆扎&#183;本&#183;拉登为什么反对美国?
  • 原文地址:https://www.cnblogs.com/seancheer/p/12588762.html
Copyright © 2011-2022 走看看