JNI学习之步步深入一
来源:互联网 发布:人工智能 蒋里博士 编辑:程序博客网 时间:2024/04/24 07:55
从接触Android的一段时间后,就经常听到JNI这个东东,刚开始,不知是由于对新事物的排斥,还是根本不把它当成一回事,就没有特地地去理他。只是在活跃的社区中零零散散地看到JNI的身影,大致知道所谓的JNI,就是一种不纯的JAVA编程技术,还需要把C/C++给扯进来。这下好了,看到需要C/C++,立马想到的是,有多远离多远。倒不是因为C/C++做过神马恐怖的勾当,而是本人C/C++技艺不精。自此,选择了逃避。
直到,面临毕业,稀里糊涂地投了一份应聘Android软件开发的岗位。当接到面试官的电话,问到“JNI是什么?”的时候,支支吾吾三言四语也说不出个你死我活。最后,面试的结果也是石沉大海,杳无音讯。从此,对JNI的讨厌之情,入骨三分,同时,又多了份感悟:JNI是个令人头痛,却又不得不学的东东。
就这样,找资料,看文档,一步步来,翻过了几座障碍,打通了Java到C的道路,那种喜悦,尽然让我哑然失笑。。。从此,觉得JNI不再那么邪恶。。。继续前行,,,后来发现,仅仅打通了道路,仅仅只能走个字符串,走个指令,想实现复杂的功能时,才知道,了解JNI的原理和规范刻不容缓,于是乎,Download一份英文JNI档案,不分昼夜地研磨,并在这里留下学习的脚印。。。
闲话少说,步入正文。
我们知道,Java应用程序是一处编码,处处运行的,之所以可以这么威风,靠的就是JVM这个东西,那什么是JVM呢,JVM乃Java虚拟机,是一种虚拟技术,位于java应用程序和特定的操作系统之间,担当着“一处编码,处处运行”的重任。他隐藏了操作系统的差异性,使得运行在上层的java程序可以不用管底层到底是神马操作系统。这样,只要你的机子上有JVM,那么你的机子就可以跑java程序,至于你用的是神马操作系统,我不用管。
可是,有滴时候,我们并不能抛开特定的操作系统的特性,而是用纯粹的java来完成我们的应用。虽然,java是多么多么滴强大,但是他也不是万能的。比如,现在我们的应用需要一些特定操作系统的特性,但是java它不支持,怎么办?或者,我们需要的部分核心功能已经存在了,但是是C/C++的库文件,更常见的一个理由是“这个处理过程性能要求高,java性能忒差,满足不了客户要求,用C/C++吧,性能高”!
如此可见,JNI的存在,总有它的理由。但是JNI的使用,我们破坏了java“一处编码,处处运行”的优势,使得我们的应用是“Host-Dependable”。同时,Java是类型安全的,而C/C++不是滴,所以,使用JNI,java这两大特性就荡然无存了。也因此,要不要使用JNI,我们需要三思而后行。。。
扯了这么远,回过头来,JNI是如何使得Java和C/C++想通的?我们知道,Java之所以不能和C/C++想通,最主要的原因就是类型差异。
关于JNI如何处理类型差异的,后面再说。这里,我们看看Java的数据类型String和C语言的Char*类型是在可见的(黑盒)层面如何相互沟通的。
我们使用Java写个类Jni.java:
- package demo.jni;
- public class Jni {
- public native int add();
- public native String getString();
- }
在使用javac编译该文件生成Jni.class文件后,我们使用javah -jni来生成一个C语言的头文件(关于javah命令的正确使用,请看我的另一个帖子),该文件名称是demo_jni_Jni.h:
- /* DO NOT EDIT THIS FILE - it is machine generated */
- #include <jni.h>
- /* Header for class demo_jni_Jni */
- #ifndef _Included_demo_jni_Jni
- #define _Included_demo_jni_Jni
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- * Class: demo_jni_Jni
- * Method: add
- * Signature: ()I
- */
- JNIEXPORT jint JNICALL Java_demo_jni_Jni_add
- (JNIEnv *, jobject);
- /*
- * Class: demo_jni_Jni
- * Method: getString
- * Signature: ()Ljava/lang/String;
- */
- JNIEXPORT jstring JNICALL Java_demo_jni_Jni_getString
- (JNIEnv *, jobject);
- #ifdef __cplusplus
- }
- #endif
- #endif
可以看到,生成的本地方法中,第一个参数类型是JNIEnv*,是一个指向JNIEnv的指针类型,那么JNIEnv是一个什么类型呢?
JNIEnv是一个指向了一个Pointer,这个Pointer指向了一张函数表,这张函数表中的每一项就是JNI中的一个函数的入口。本地的方法通过查找这张表来调用某个jni函数,来和JVM交互。如图:
第二个参数,如果申明的方法是static类型的,则该参数是一个jclass类型,如果申明的方法是一个非static类型的,则该参数是一个jobject类型。
如果你的方法含有参数,那么从第三个参数开始,就是申明时方法的参数了。
- JNI学习之步步深入一
- JNI学习之步步深入一
- JNI学习之步步深入一
- JNI学习之步步深入一
- JNI学习之步步深入二
- JNI学习之步步深入三
- JNI学习之步步深入二
- JNI学习之步步深入二
- JNI学习之步步深入三
- NDK---JNI学习步步深入之二
- JNI学习之步步深入二
- JNI学习之步步深入三
- JNI学习之步步深入四--皇后的祝福
- JNI学习之步步深入四--皇后的祝福
- JNI学习之步步深入四--皇后的祝福
- JNI学习之步步深入四--皇后的祝福
- NDK---JNI学习步步深入之一
- JNI步步深入
- Windos下IIS7+Tomcat整合从零做起
- Java反射机制简介及简单实例
- Android NDK调试定位错误
- netperf的时间测量值得分析
- 一个真实的项目例子
- JNI学习之步步深入一
- Flex 如何实现按钮之间的切换,按钮点击事件
- 论证谁才是IT 职业教育的领导品牌
- 开发项目中的28原则
- 线程安全和可重入性以及线程安全函数
- android中霍夫变换检测圆
- JNI学习之步步深入二
- 逻辑运算的短路问题
- 【objc】基础结构objc_class的布局,老版本vs新版本