访问实例域¶
代码实现¶
假设我们有一个FisherTom
类,里面有money
。Java方法addMoney()
表示“增加money”。
进行一些运算后改变了money
的值。
private double money = 100;
static {
System.loadLibrary("fisher-pole");
}
public double addMoney() {
money = money * 1.2 + 4;
return money;
}
public native double nAddMoney();
我们想用C++代码来实现“增加money”的功能。新建一个本地方法nAddMoney()
。
extern "C"
JNIEXPORT jdouble JNICALL
Java_com_rustfisher_fishpole_worker_FisherTom_nAddMoney(JNIEnv *env, jobject thiz) {
jclass tom_clz = env->GetObjectClass(thiz); // 获取到这个Java类
jfieldID money_fid = env->GetFieldID(tom_clz, "money", "D"); // 获取到属性id
jdouble money = env->GetDoubleField(thiz, money_fid); // 获取到当前值
money = money * 1.2 + 4.2; // 简单的运算
env->SetDoubleField(thiz, money_fid, money); // 把值存进去
return money;
}
- 在C++代码中,先调用
GetObjectClass
方法获取到jclass,也就是对应的Java类。 - 然后找到
money
的jfieldID,这样才能直接操作它。 - 读取和设置
money
的数值,分别用GetDoubleField
和SetDoubleField
方法。 SetDoubleField
之后,在Java层,我们可以看到money
的数值已经被修改了。
通过以上例子,我们了解如何用C++修改对象里的属性。
分析¶
下面我们来仔细看一下Java_com_rustfisher_fishpole_worker_FisherTom_nAddMoney(JNIEnv *env, jobject thiz)
第二个参数是jobject
类型。实际上,它和Java中的this引用等价。
静态方法得到的是类的引用,而非静态方法得到的是对隐式的this参数对象的引用。
现在,我们访问private double money
。
JNI 要求程序员通过调用特殊的JNI函数来获取和设置数据的值。
在我们的例子里,要使用GetdoubleField
和SetDoubleField
函数,因为money
是double类型的。
对于其他类型,可以使用的函数有:
GetIntField
/SetIntField
;GetObjectField
/SetObjectField
等等。
其通用语法是:
这里,fieldID
是一个特殊类型jfieldID
的值,jfieldID
标识结构中的一个域,而Xxx代表Java数据类型(Object, Boolean, Byte 或其他)。为了获得fieldID
,必须先获得一个表示类的值,有两种方法可以实现此目的。
GetObjectClass
函数可以返回任意对象的类。
例如:
FindClass
函数可以让你以字符串形式来指定类名(有点奇怪的是,要以/代替句号作为包名之间的分隔符)。
之后,可以使用GetFieldID
函数来获得fieldID。
必须提供域的名字、它的签名以及它的类型的编码。
例如,下面是从money
域得到域ID的代码:
你可能会认为访问数据域相当令人费解。JNI的设计者不想把数据域直接暴露在外,所以他们不得不提供获取和设置数据域值的函数。 为了使这些函数的开销最小化,从域名计算域ID (代价最大的一个步骤)被分解出来作为单独的一步操作。 也就是说,如果你反复地获取和设置一个特定的城,你计算域标识符的开销就只有一次。
本站说明
一起在知识的海洋里呛水吧。广告内容与本站无关。如果喜欢本站内容,欢迎投喂作者,谢谢支持服务器。如有疑问和建议,欢迎在下方评论~