10.3 Confusing jclass with jobject
注意:不要混淆jclass和jobject
Class references(类引用) correspond to java.lang.Class instances, which represent class types.
Instance references(实例引用) correspond to arrays and instances of java.lang.Object or one of its subclasses. 
An operation such as GetFieldID, which takes a jclass, is a class operation because it gets the field descriptor from a class. 
In contrast, GetIntField, which takes a jobject, is an instance operation because it gets the value of a field from an instance.
10.4 Truncating(截断) jboolean Arguments
注意:截断jboolean类型
jboolean是一个8位的unsigned类型,值范围为0~255.0对应JNI_FALSE,1~255对应JNI_TRUE.
对于32位或16位的变量a赋值给jboolean时,如果a的低8位为0会出现逻辑问题.
代码:
void print(jboolean condition)
{
    if (condition) {
        printf("true\n");
    } else {
        printf("false\n");
    }
}
//错误
int n = 256;
print (n);             //==>JNI_FALSE
对于32位变量n(256的低8位为0),本应该判断为JNI_TRUE,实际判断为JNI_FLASE.
改为如下后逻辑正确:
//正确
int n = 256;
print(n ? JNI_TRUE : JNI_FALSE);
10.6 Confusing IDs with References
注意:不要混淆ID和引用
The JNI exposes objects as references. Classes, Strings, and Arrays are special types of references. 
The JNI exposes methods and fields as IDs. An ID is not a reference.
Native code may create multiple references that refer to the same object.
In contrast, a unique field or method ID is derived for the same definition of a field or a method. 
If class A defines method f and class B inherits f from A, the two GetMethodID calls in the following code always return the same result:
jmethodID MID_A_f = (*env)->GetMethodID(env, A, "f", "()V");
jmethodID MID_B_f = (*env)->GetMethodID(env, B, "f", "()V");
10.7 Caching Field and Method IDs     缓存域ID(Filed ID)和方法ID(Method ID)
下面举例说明了没有缓存域ID可能带来的bug:
class C {
    private int i;
    native void f();
}
(1)不缓存域ID:
1) 获取对象的类,GetObjectClass.
2) 找出变量i的域ID, GetFieldID.
3) 基于域ID获取域值, GetIntField.
// No field IDs cached.
JNIEXPORT void JNICALL Java_C_f(JNIEnv *env, jobject this) {
    jclass cls = (*env)->GetObjectClass(env, this);
    jfieldID fid = (*env)->GetFieldID(env, cls, "i", "I");
    int ival = (*env)->GetIntField(env, this, fid);
}
如果我们定义C类的子类D,D类里也声明一个变量i,会出现问题:
// Trouble in the absence of ID caching
class D extends C {
    private int i;
    D() {
        f();         // inherited from C
    }
}
当D的构造函数调用C的接口f时,native接口Java_C_f里的jobject参数是D的对象,cls指向D类,fid代表的是D.i。所以ival里的值是D.i而不是C.i。这可能不是我们想要的。
如何解决?
(2)缓存域ID:
解决办法是当你确定要使用哪个类时,缓存对应的域ID。见如下代码:
// Version that caches IDs in static initializers
class C {
    private int i;
    native void f();
    private static native void initIDs();
    static {
        initIDs();         // Call an initializing native method
    }
}
static jfieldID FID_C_i;        //缓存域ID
JNIEXPORT void JNICALL Java_C_initIDs(JNIEnv *env, jclass cls) {
    /* Get IDs to all fields/methods of C that native methods will need. */
    FID_C_i = (*env)->GetFieldID(env, cls, "i", "I");
}
JNIEXPORT void JNICALL Java_C_f(JNIEnv *env, jobject this) {
    int ival = (*env)->GetIntField(env, this, FID_C_i);
    /* ival is always C.i, not D.i */
}
域ID缓存在C类的静态方法initIDs里。这就保证了 FID_C_i缓存的是C类变量i的域.
10.8 Terminating(结束) Unicode Strings
用GetStringChars或GetStringCritical接口获取的Unicode字符串不是以null结尾的。一般用GetStringLength来获取Unicode字符串的长度。
10.11 Retaining Virtual Machine Resources 防止内存泄漏
A common mistake in native methods is forgetting to free virtual machine resources. 
JNIEXPORT void JNICALL
Java_pkg_Cls_f(JNIEnv *env, jclass cls, jstring jstr)
{
const jchar *cstr =
(*env)->GetStringChars(env, jstr, NULL);
if (cstr == NULL) {
    return;
}
...
if (...) { /* exception occurred */
    /* misses a ReleaseStringChars call */
    return;
}
...
/* normal return */
(*env)->ReleaseStringChars(env, jstr, cstr);
}

[2019.12.9]chapter10 Traps and Pitfalls相关推荐

  1. DayDayUp:2019.12.30吴晓波2020年终秀演讲《预见2020:来海边,拾起信心》读后有感

    DayDayUp:2019.12.30吴晓波2020年终秀演讲<预见2020:来海边,拾起信心>读后有感 导读:2019年,过的好不好?有人豪情万丈,有人强颜欢笑. 互联网平台带来了方便快 ...

  2. java中int边界值_数组中重复的数字2019.12.06

    记录一下,记录一下,记录一下,因为我的记忆好像只有10s 题目描述: 在一个长度为n的数组里面,所有元素的范围是[0,n-1],数组中可能存在某些数字是重复的,请判断是否有重复元素,如果有,找出来. ...

  3. 2019.12.31大一练习赛

    2019.12.31大一练习赛 寒假培训第一天,老师认为我们题做得太快了,于是晚上搞了一场练习赛. 第1题 QWQ和QAQ Description QWQ的朋友QAQ开了一个A工厂,但QAQ不是一个很 ...

  4. 每日启程——2019.12.11日(草木有本心,何求美人折)

    每日启程--2019.12.11日(草木有本心,何求美人折) 今天是我写每日启程的第二天.起床的时候还算比较精神,不过到了实验室还是有点困意的.怎么说了有一丝丝的疲倦和懒惰.但这也是人之常情克服一下就 ...

  5. 主流RGBD数据集简介 2019.12.15

    RGBD 数据集简介,2019.12.15 NYU Depth Dataset V2(3D分割任务) 数据集地址: https://cs.nyu.edu/~silberman/datasets/nyu ...

  6. 每日启程——2019.12.15(纸上谈来终觉浅,绝知此事要躬行。)

    每日启程--2019.12.15(纸上谈来终觉浅,绝知此事要躬行.) 早上本来想多睡一会.没想到对面的工地可不答应.硬是一锤一锤的把我叫醒.好吧,谁叫我昨天晚上睡得太晚了呢.不过呢.昨天没有做启程和总 ...

  7. 2019.12.18

    2019.12.18 bool canBeEqual(vector<int>& target, vector<int>& arr) {if (target.si ...

  8. 每日启程——2019.12.13(古人学问无遗力,少壮工夫老始成)

    每日启程--2019.12.13(古人学问无遗力,少壮工夫老始成) 昨天,可以说是放飞了自我.好在今天又按时回来工作了,算是收好了心.不过我觉得,真的需要一个良好的睡眠.不然的话,我真的容易被自己心中 ...

  9. C陷阱和缺陷(C Traps and Pitfalls)-读书笔记

    C Traps and Pitfalls Chap 01 词法陷阱 1.=是赋值运算符,==表示相等判断. 2.&.|是位运算符号,&&.||是逻辑运算符. 3.词法分析的贪心 ...

最新文章

  1. Java后台解析前台的get中文请求
  2. 利用FFT计算非平稳随机信号WVD分布
  3. 26-Ubuntu-文件和目录命令-其他命令-管道
  4. winpe镜像文件iso下载_下载:微软正式发布Win10 2004版并即日起开始推送
  5. 安卓开发笔记(十):升级ListView为RecylerView的使用
  6. Web API-基本认知
  7. python 计算协方差_Python3Numpy——相关性协方差应用
  8. Mybatis中insert之后返回主键
  9. 图形交互界面_室内量房APP哪家强?5款软件深度测评(界面UI体验篇)
  10. 微信小程序sass不编译怎么办_不吹牛,四款免费实用的微信小程序,打开立即使用!...
  11. 局域网带宽控制解决方案 P2P终结者使用详解
  12. sysmain服务怎么启动 Win7 SuperFetch无法启动
  13. HDU 3709 平衡数 数位dp(Java版)
  14. 《史蒂夫·乔布斯传》——童年篇有感
  15. DropDownMenu下拉菜单
  16. 两团队在《自然》上发布重要抗癌研究成果,消化系统肿瘤或有望治愈...
  17. 谈谈8583报文的使用及测试
  18. iOS常用功能 - 根据链接生成二维码图片
  19. 绕过CDN查询真实IP方法
  20. 【计算机网络面试高频】-HTTP协议详解,HTTP协议常见问题

热门文章

  1. 上海亚商投顾:沪指失守3000点 半导体、白酒领跌两市
  2. oracle细粒度(fga)审核
  3. 桥接模式(Bridge模式)详解
  4. 视通助力中国航天某院多媒体会议室建设
  5. Win10系统hosts文件
  6. C# 将PPT文件转换成PDF文件
  7. c语言中len的作用,C语言 int len( )  求大神解释
  8. ###数字形式转换1
  9. OpenMLDB + OneFlow: 手把手教你快速链接特征工程到模型训练
  10. php一年过去多少天,php 显示今天是星期几与一年的每几天代码