继续本地调用的相关知识。前面已经讲过了关于java如何调用下面的相关知识,包括如何适配变量,jni调用的方法规范,以及一些jni方法调用的注意事项等等。
根据前面的介绍,我们可以发现,调用的过程,如果真的使用起来,并没有很顺手,因为仅仅只有参数的向下传递是绝对不够的。我们不仅要下层的代码访问上层的,还要来回调用彼此之间的方法,这样做才够cool嘛。而且才能灵活满足各种需求。就像佛经所说:能进能退,乃真正法器(形容能进能退,进退有度,赵云式的霸气),有木有?
那先来介绍下访问实例域吧。在java程序中,有很多方法,会使用到类中的全局变量,比如下面的代码:
class Employee{
double salary = 0;
public void raiseSalary(double byPercent){
salary += 1 + byPercent / 100;
}
}
很常见的方法吧?现在呢,我们要把这个raiseSalary变成一个本地方法。根据前面内容,javah可以生成一个如下方法
JNIEXPORT void JNICALL Java_Employee_raiseSalary(JNIEnv *, jobject, jdouble)
看到这个方法,你能看出和先前讲得有什么不同么?什么?能进能退?我代表赵云,给你跪了。。。咳,我们看到,有两个不同处,第一个,salary变量是一个Employee的变量,并没有被通过参数传入到c层中。这个我们要稍后重点介绍。还有一个,看看第二个传入参数,可以看到,前面由于使用的是static静态方法,所以,传递进来的是jclass,而这里,我们看到传进来的是
jobject。这个也很合理,因为静态方法是没有对象的嘛。
好了,有java对象传下来,后面就很好想象了,对吧。不过,直接访问要求虚拟机暴露它们的内部数据布局,因此,JNI要求程序员通过调用特殊的JNI函数来获取和设置数据的值。这里我们要使用GetdoubleField和SetDoubleField函数,当然还有其他类型,一般语法是:
x = (*env)->GetXxxField(env, this_obj, fieldID);
(*env)->SetXxxField(env, this_obj, fieldID, x);
这里,又产生了两个疑问,一个是
fieldID是个什么东东?还有,GetObjectField方法返回的对象,我们用什么class定义它?
先看看FieldID,它是一个特殊类型的值,fieldID表示结构中的一个域。使用GetFieldID函数来获得fieldID。
jfieldID id_salary = (*env)->GetFieldID(env, class_Employee, "salary", "D");
字符串"D"表示类型是double。这个后面介绍。
感觉有点像纹理id有没有?JNI的设计者不想把数据域直接暴露在外,所以,他们不得不提供获取和设置数据域值的函数。为了使这些函数的开销最小化,从域名计算域ID(代价最大的一个步骤)被分解出来作为单一步骤。这样,如果你反复获取和设置一个特定的域,你计算域标示符的开销只有一次。
第二点,如何得到一个class?jni有两种方式得到class:
jclass class_Employee = (*env)->GetObjectClass(env, this_obj);
FindClass函数可以让你以字符串形式来指定类名(很奇怪的是使用/来代替包分割符号.)
jclass class_String = (*env)->FindClass(env, "java/lang/String");
看起来有点像反射,是吧。(越往后看,其实jni的java层的method调用也是反射的形式,他们分别对应了反射的field和method)
好了,大概介绍完了如何访问java的域,我们最后做个总结,把开始的方法完全转换成jni层的代码:
JNIEXPORT void JNICALL Java_Employee_raiseSalary(JNIEnv* env, jobject this_obj, jdouble byPercent){
jclass class_Employee = (*env)->GetObjectClass(env, this_obj);
jfieldID id_salary = (*env)->GetFiledID(env, class_Employee, "salary", "D");
jdouble salary = (*env)->getDoubleField(env, this_obj, id_salary);
salary += 1 + byPercent;
(*env)->SetDoubleField(env, this_obj, id_salary, salary);
}
分享到:
相关推荐
调用iphlpapi获得本地ip信息,C++源代码演示获取ip信息的全过程。
通过本地方法调用来调用C语言的例子,一个调用时间的,谨供参考
Android中调用js方法及js中调用本地方法,简单明了
3,test.html 要在运行在容器里(tomcat,resin XXXX),本地直接打开是执行不了的,我折腾了好久才弄懂这个问题的 注,chrome 通过注册表注册表 只能调用本地的 exe 或者bat文件,不能调用 ppt word 这样的问题,...
JS和Android本地方法之间的调用
【方法】html调用本地python程序进行交互 前后端交互
java调用本地打印机java调用本地打印机java调用本地打印机java调用本地打印机
web调用本地应用程序
js通过webview调用android的本地方法,避免addJavascriptInterface问题
JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式 )。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各...
jni本地调用4
delphi编程实现调用本地程序,本实例可调用本地 截图工具、步骤记录器、画图工具、计算器、记事本、屏幕键盘、放大镜、任务管理器、命令提示符、控制面板、word和excel,用的是WinExec和ShellExecute方法,需要实现...
1、Dubbo 远程调用实现 2、内带zookeeper-3.4.5消息服务 3、直接导入myeclipse运行:dubbo-server导入tomcat中运行 4、dubbo-client 运行测试类/dubbo-client/src/com/fengjx/main/Consumer.java
借助WebSocket完成Android本地代码调用JavaScript代码的插件,并且可以获得返回值
该文档详细介绍了在Java代码中如何调用C或C++代码。主要思想是:将C或C++代码大包成动态链接库,然后共Java代码在执行时调用。
本地摄像头调用api
做过iOS的都知道,使用UIWebView进行布局有一个非常头疼的问题:就是js调用本地代码!这个功能其实还很常用,比如某些APP需要有扫描二维码的功能,如果使用UIWebView布局,怎么告诉APP现在要执行本地代码呢? 本资源...
通过Java调用本地方法.pdf