缓存字段和方法ID
来源:互联网 发布:python宝典 pdf 编辑:程序博客网 时间:2024/05/21 22:46
获取字段或方法ID时,需要用字段、方法的名字和描述进行一个检索。检索过程比较耗时,可以通过缓存技术来减少这个过程带来的消耗。
缓存字段ID和方法ID的方法主要有两种。
1.使用时缓存
2.定义字段和方法的类静态初始化时缓存
使用时缓存
字段或方法ID在字段的值被访问或者方法被回调的时候缓存起来。
1.先定义两个native方法
//缓存字段(使用时) public native void cacheFieldWhenUse(); //缓存方法ID(使用时) public native String cacheMethodWhenUse(char[] chars);
2.生成c头文件
JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_cacheFieldWhenUse(JNIEnv *, jobject);JNIEXPORT jstring JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_cacheMethodWhenUse (JNIEnv *, jobject, jcharArray);
3.方法实现
3.1缓存字段
下面方法主要实现的是:获取name字段值并修改。
JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_cacheFieldWhenUse (JNIEnv *env, jobject jobj){ //0.静态变量,用于缓存fid static jfieldID fid = NULL; //1.获取jclass jclass cls = (*env).GetObjectClass(jobj); //2.获取name的fid if(fid == NULL){ fid = (*env).GetFieldID(cls, "name", "Ljava/lang/String;"); //获取失败 if(fid == NULL){ return; //error } } //3.获取name字段值 jstring jstr = (jstring) (*env).GetObjectField(jobj, fid); //4.将字符串转换成字符指针 const char *str = (*env).GetStringUTFChars(jstr, NULL); //4.1如果为NULL,则发生了内存溢出 if(str == NULL){ return; //out of memory } //5.将str字符添加到str_new后面 char *c = "缓存字段测试 "; char new_char[strlen(str) + strlen(c)]; //复制c_str 到 new_char strcpy(new_char, c); strcat(new_char, str); //6.及时释放str (*env).ReleaseStringUTFChars(jstr, str); //7.重新生成jstr jstr = (*env).NewStringUTF(new_char); //7.1如果为NULL,则发生了内存溢出 if(jstr == NULL){ return; //out of memory } //8.修改name字段值 (*env).SetObjectField(jobj, fid, jstr);};
3.2缓存方法ID
下面的方法实现的是将java中传递过来的字符数组转换成字符串返回
JNIEXPORT jstring JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_cacheMethodWhenUse (JNIEnv *env, jobject jobj, jcharArray elemArr){ //1.要缓存的方法ID:cid static jmethodID cid = NULL; //2.获取String的jclass jclass stringClass = (*env).FindClass("java/lang/String"); if(stringClass == NULL){ return NULL; //exception } //3.判断cid是否已经初始化 if(cid == NULL){ cid = (*env).GetMethodID(stringClass, "<init>", "([C)V"); if(cid == NULL){ return NULL; //exception } } //4.把传入的字符数组转换成字符串 jstring result = (jstring) (*env).NewObject(stringClass, cid, elemArr); //5.本地引用引用 /* free local references */ (*env).DeleteLocalRef(elemArr); (*env).DeleteLocalRef(stringClass); //6.返回字符串 return result;};
java中调用
Log.i(TAG, "------------------------------------------"); Log.i(TAG, "name修改前: " + jd.name); jd.cacheFieldWhenUse(); Log.i(TAG, "name修改后: " + jd.name); Log.i(TAG, "------------------------------------------"); char[] chars = {'a', 'b', 'c'}; Log.i(TAG, "result传入:{'a', 'b', 'c'}"); String result = jd.cacheMethodWhenUse(chars); Log.i(TAG, "result输出:" + result); Log.i(TAG, "------------------------------------------");
输出结果
09-29 12:41:42.431 25020-25020/com.test.git.jnidemo I/MainActivity-: ------------------------------------------09-29 12:41:42.431 25020-25020/com.test.git.jnidemo I/MainActivity-: name修改前: changed Lucy09-29 12:41:42.431 25020-25020/com.test.git.jnidemo I/MainActivity-: name修改后: 缓存字段测试 changed Lucy09-29 12:41:42.431 25020-25020/com.test.git.jnidemo I/MainActivity-: ------------------------------------------09-29 12:41:42.431 25020-25020/com.test.git.jnidemo I/MainActivity-: result传入:{'a', 'b', 'c'}09-29 12:41:42.431 25020-25020/com.test.git.jnidemo I/MainActivity-: result输出:abc09-29 12:41:42.431 25020-25020/com.test.git.jnidemo I/MainActivity-: ------------------------------------------
tips
上面的方法多次调用的时候缓存的字段或方法只会初始化一次,因而提高了效率。
类的静态初始化过程中缓存字段和方法 ID
1.先写两个native方法
//缓存(初始化时) public static native void cacheWhenInit(); //使用上面方法的缓存 public native String cacheWhenInitInvoke(char[] chars);
2.生成相应的头文件
JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_cacheWhenInit (JNIEnv *, jclass);JNIEXPORT jstring JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_cacheWhenInitInvoke (JNI
3.方法实现
3.1缓存jmethodID
//缓存的String的String(char value[])方法idjmethodID strInitID;JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_cacheWhenInit (JNIEnv *env, jclass jcls){ //1.获取String的jclass jclass strClass = (*env).FindClass("java/lang/String"); if(strClass == NULL){ return; //exception } //2.判断cid是否已经初始化 if(strInitID == NULL){ strInitID = (*env).GetMethodID(strClass, "<init>", "([C)V"); if(strInitID == NULL){ return; //exception } }};
3.2直接使用3.1缓存的ID
//使用上面的strInitIDJNIEXPORT jstring JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_cacheWhenInitInvoke (JNIEnv *env, jobject jobj, jcharArray chars){ jclass stringClass = (*env).FindClass("java/lang/String"); //把传入的字符数组转换成字符串 return (jstring) (*env).NewObject(stringClass, strInitID, chars);};
4.JAVA调用过程
4.1首先初始化时调用
static { System.loadLibrary("NdkJniDemo"); cacheWhenInit(); }
4.2在其他地方直接使用
Log.i(TAG, "------------------------------------------"); Log.i(TAG, "result传入:{'a', 'b', 'c'}"); result = jd.cacheWhenInitInvoke(chars); Log.i(TAG, "result输出:" + result); Log.i(TAG, "------------------------------------------");
4.3输出结果:
09-29 12:41:42.431 25020-25020/com.test.git.jnidemo I/MainActivity-: ------------------------------------------09-29 12:41:42.431 25020-25020/com.test.git.jnidemo I/MainActivity-: result传入:{'a', 'b', 'c'}09-29 12:41:42.431 25020-25020/com.test.git.jnidemo I/MainActivity-: result输出:abc09-29 12:41:42.431 25020-25020/com.test.git.jnidemo I/MainActivity-: ------------------------------------------
两种缓存方式对比
如果JNI程序员不能控制方法和字段所在的类的源码的话,在使用时缓存是个合理的方案。
比起静态初始时缓存来说,使用时缓存有一些缺点:
1.使用时缓存的话,每次使用时都要检查一下。
2.方法ID和字段ID在类被unload时就会失效,如果你在使用时缓存ID,你必须确保只要本地依赖于这个ID的值,那么这个类不会被unload。另一方面,如果缓存发生在静态初始化时,当类被unload和reload时,ID会被重新计算。
因此,尽可能在静态初始化时缓存字段ID和方法ID
0 0
- 缓存字段和方法ID
- JNI由浅入深_8_JNI缓存字段和方法ID
- 合并id字段和value
- Nhibernate 之 一级缓存: Get(Id) 和 Load(Id)
- 类、字段和方法
- tp add和save无效 字段缓存
- hibernate使用annotation配置时将@Id配置到字段field上和get方法上的区别
- EASBOS根据id获取对象方法来进行过滤字段
- 如何让外键表中的字段和主键表的ID一致
- 字段摘要和方法摘要
- mysql 查找数据库里面字段的id是否存在 可以限定表和字段
- getLastModified()方法和浏览器缓存
- JavaScript更改class和id的方法
- C16_OC06-id关键字和构造方法
- JavaScript更改class和id的方法
- oc中的id关键字和构造方法
- OC--Id和构造方法
- 微信小程序缓存,根据不同的id来进行设置和读取缓存
- js函数中隐藏一个div
- -Dmaven.multiModuleProjectDirectory system property is not set
- [Leetcode] Remove Element
- c# 利用 splitcontainer 和treeview 在MDI上面显示窗体 (进阶)
- spring中各种经典的注解
- 缓存字段和方法ID
- ELK stack实战之结合rsyslog分析系统日志(auth.log)
- 外星人的密码数字
- 利用MAVEN打包可运行jar包,包括依赖的第三方包
- ggplot2 分面多数据源组合示例
- NodeJs 安装静态的文件服务
- 【Python专题】 使用pycharm+pyqt5 控件事件触发
- 可扩展的web单页应用程序架构
- Andriod Studio基础界面设计