JNI笔记 JNI引用,异常处理,初始化成员变量
2017-06-14 16:43
274 查看
1 回收局部引用变量
局部引用,通过DeleteLOcalREf手动释放对象
c代码
java代码
使用场景
访问一个较大的java对象,使用完了之后,还要进行复杂的耗时操作
创建了大量的局部引用,占用了太多的内存,而且这些局部引用跟后面的操作没有关联性
2 回收局部引用变量
c代码
java代码
打印结果
3 异常处理
保证Java代码可以运行
补救措施保证C代码继续运行
JNI自己抛出的异常,在Java层无法捕捉,只能在C层清空
用户通过TrowNew抛出的异常,可以在Java层捕捉
c代码
成员变量里的名字为field但是我这里写成了aa
执行后报错
c代码
打印结果
虽然aa的成员变量没有找到,但是并没有抛出异常。因为把异常清空了。通过找到了名字对应的field的成员变量,并对比成员变量的值,在不相等的情况下手动抛出了一个异常。
打印的结果第一个是捕获的异常,第二个是程序直接crash。因为没有捕获。
4 缓存
c代码
java代码
打印结果
可以看出,key_id 只初始化了一次。
5 初始化成员变量
初始化全局变量 动态库家在完成之后 立刻缓存起来
c代码
java代码
局部引用,通过DeleteLOcalREf手动释放对象
c代码
JNIEXPORT void JNICALL Java_com_yeliang_JniTest_localRef(JNIEnv *env, jobject jobj){ int i = 0; //模拟:循环创建对象 for (;i<5;i++){ jclass cls = (*env)->FindClass(env,"java/util/Date"); jmethodID constructor_mid = (*env)->GetMethodID(env,cls,"<init>","()V"); //创建Date对象 jobject obj = (*env)->NewObject(env, cls, constructor_mid); //不在使用jobject对象了 //通知垃圾回收期回收这些对象 (*env)->DeleteLocalRef(env,obj); } }
java代码
JniTest jniTest = new JniTest(); public static void main(String[] args) { JniTest jniTest = new JniTest(); jniTest.localRef(); }
使用场景
访问一个较大的java对象,使用完了之后,还要进行复杂的耗时操作
创建了大量的局部引用,占用了太多的内存,而且这些局部引用跟后面的操作没有关联性
2 回收局部引用变量
c代码
jstring global_str; //创建 JNIEXPORT void JNICALL Java_com_yeliang_JniTest_createGlobalRef(JNIEnv *env, jobject jobj){ jstring obj = (*env)->NewStringUTF(env,"russul westbruk is so powerful!"); global_str = (*env)->NewGlobalRef(env,obj); } //获得 JNIEXPORT void JNICALL Java_com_yeliang_JniTest_getGlobalRef(JNIEnv *env, jobject jobj){ return global_str; } //释放 JNIEXPORT void JNICALL Java_com_yeliang_JniTest_deleteGlobalRef(JNIEnv *env, jobject jobj){ (*env)->DeleteGlobalRef(env,global_str); }
java代码
public native void createGlobalRef(); public native String getGlobalRef(); public native void deleteGlobalRef(); public static void main(String[] args) { JniTest jniTest = new JniTest(); jniTest.createGlobalRef(); System.out.println(jniTest.getGlobalRef()); jniTest.deleteGlobalRef(); }
打印结果
russul westbruk is so powerful!
3 异常处理
保证Java代码可以运行
补救措施保证C代码继续运行
JNI自己抛出的异常,在Java层无法捕捉,只能在C层清空
用户通过TrowNew抛出的异常,可以在Java层捕捉
c代码
JNIEXPORT void JNICALL Java_com_yeliang_JniTest_exception(JNIEnv *env, jobject jobj){ jclass cls = (*env)->GetObjectClass(env,jobj); jfieldID fid = (*env)->GetFieldID(env,cls,"aa","Ljava/lang/String"); }
成员变量里的名字为field但是我这里写成了aa
public String field = "yeliang"; public static void main(String[] args) { JniTest jniTest = new JniTest(); try{ jniTest.exception(); }catch(Exception e){ System.out.println("发生异常:"+e.getMessage()); } jniTest.exception(); }
执行后报错
Exception in thread "main" java.lang.NoSuchFieldError: aa
c代码
JNIEXPORT void JNICALL Java_com_yeliang_JniTest_exception(JNIEnv *env, jobject jobj){ jclass cls = (*env)->GetObjectClass(env,jobj); jfieldID fid = (*env)->GetFieldID(env, cls, "aa", "Ljava/lang/String;"); //检测是否发生java异常 jthrowable exception = (*env)->ExceptionOccurred(env); if (exception!=NULL){ //让java代码可以继续运行 (*env)->ExceptionClear(env); //补救措施 fid = (*env)->GetFieldID(env, cls, "field", "Ljava/lang/String;"); } //获取属性的值 jstring jstr = (*env)->GetObjectField(env,jobj,fid); char *str = (*env)->GetStringUTFChars(env,jstr,NULL); //对比属性值是否合法 // ==0相等 if (_stricmp(str, "give me the ball") != 0){ //认为抛出异常,给java层处理 jclass newexcls = (*env)->FindClass(env,"java/lang/IllegalArgumentException"); (*env)->ThrowNew(env,newexcls,"key's value is invalid"); } }
打印结果
发生异常:field's value is invalid Exception in thread "main" java.lang.IllegalArgumentException: field's value is invalid
虽然aa的成员变量没有找到,但是并没有抛出异常。因为把异常清空了。通过找到了名字对应的field的成员变量,并对比成员变量的值,在不相等的情况下手动抛出了一个异常。
打印的结果第一个是捕获的异常,第二个是程序直接crash。因为没有捕获。
4 缓存
c代码
JNIEXPORT void JNICALL Java_com_yeliang_JniTest_cache(JNIEnv *env, jobject jobj){ jclass cls = (*env)->GetObjectClass(env,jobj); //获取ffiedID只获取一次 //局部静态变量 static jfieldID key_id = NULL; if (key_id==NULL){ key_id = (*env)->GetFieldID(env, cls, "field", "Ljava/lang/String;"); printf("========GetFieldID===========\n"); } }
java代码
public static void main(String[] args) { JniTest jniTest = new JniTest(); jniTest.cache(); }
打印结果
========GetFieldID===========
可以看出,key_id 只初始化了一次。
5 初始化成员变量
初始化全局变量 动态库家在完成之后 立刻缓存起来
c代码
jfieldID field; jmethodID random_mid; JNIEXPORT void JNICALL Java_com_yeliang_JniTest_initIds(JNIEnv *env, jclass jcls){ field = (*env)->GetFieldID(env, jcls, "field", "Ljava/lang/String;"); random_mid = (*env)->GetMethodID(env,jcls,"getRandomInt","(I)I"); }
java代码
public String field = "yeliang"; public int getRandomInt(int range){ System.out.println("Java中的方法执行了"); return new Random().nextInt(range); } static{ System.loadLibrary("jni_study"); initIds(); }
相关文章推荐
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
- C++ 类中的引用成员变量初始化
- 类的常成员变量和引用类型的成员的定义和初始化相关知识点
- C++特殊成员变量(静态、常量、引用)的初始化方法
- IO异常处理规范,创建流对象。在try外创建流对象的引用。在try内对流对象进行初始化。
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
- IO异常处理规范,创建流对象。在try外创建流对象的引用。在try内对流对象进行初始化。
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
- 如何初始化引用类型的成员变量
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
- 【转】C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法 --转
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
- C# 引用其他命名空间的公共变量时的警告:由于"***"是引用封送类的字段,访问上面的成员可能导致运行时异常
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法