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:

[java] view plaincopy
  1. package demo.jni;  
  2. public class Jni {  
  3.       
  4.     public native int add();  
  5.     public native String getString();  
  6. }  

 

在使用javac编译该文件生成Jni.class文件后,我们使用javah -jni来生成一个C语言的头文件(关于javah命令的正确使用,请看我的另一个帖子),该文件名称是demo_jni_Jni.h:

 

[cpp] view plaincopy
  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class demo_jni_Jni */  
  4. #ifndef _Included_demo_jni_Jni  
  5. #define _Included_demo_jni_Jni  
  6. #ifdef __cplusplus  
  7. extern "C" {  
  8. #endif  
  9. /* 
  10.  * Class:     demo_jni_Jni 
  11.  * Method:    add 
  12.  * Signature: ()I 
  13.  */  
  14. JNIEXPORT jint JNICALL Java_demo_jni_Jni_add  
  15.   (JNIEnv *, jobject);  
  16. /* 
  17.  * Class:     demo_jni_Jni 
  18.  * Method:    getString 
  19.  * Signature: ()Ljava/lang/String; 
  20.  */  
  21. JNIEXPORT jstring JNICALL Java_demo_jni_Jni_getString  
  22.   (JNIEnv *, jobject);  
  23. #ifdef __cplusplus  
  24. }  
  25. #endif  
  26. #endif  

 

可以看到,生成的本地方法中,第一个参数类型是JNIEnv*,是一个指向JNIEnv的指针类型,那么JNIEnv是一个什么类型呢?

JNIEnv是一个指向了一个Pointer,这个Pointer指向了一张函数表,这张函数表中的每一项就是JNI中的一个函数的入口。本地的方法通过查找这张表来调用某个jni函数,来和JVM交互。如图:

 

TTT

 

 

第二个参数,如果申明的方法是static类型的,则该参数是一个jclass类型,如果申明的方法是一个非static类型的,则该参数是一个jobject类型。

 

如果你的方法含有参数,那么从第三个参数开始,就是申明时方法的参数了。

0 0
原创粉丝点击