Java通过JNI调用C语言的方法

来源:互联网 发布:c语言二分法求方程例题 编辑:程序博客网 时间:2022/06/29 20:26

Java通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使Java可以实现和本地机器的紧密联系,调用系统级的各接口方法。

简单介绍及应用如下:

一、Java中所需要做的工作

在Java程序中,首先需要在类中声明所调用的库名称,如下:

Java代码

  1. static {        
  2. System.loadLibrary(“goodluck”);        
  3. }    
  4. static {   
  5. System.loadLibrary(“goodluck”);   

在这里,库的扩展名字可以不用写出来,究竟是DLL还是SO,由系统自己判断。

还需要对将要调用的方法做本地声明,关键字为native。并且只需要声明,而不需要具体实现。如下:

Java代码

  1. public native static void set(int i);      
  2. public native static int get();     
  3. public native static void set(int i);   
  4. public native static int get();  

然后编译该Java程序文件,生成CLASS,再用JavaH命令,JNI就会生成C/C++的头文件。

例如程序testdll.Java,内容为:

Java代码

  1. public class testdll      
  2. {      
  3. static      
  4. {      
  5. System.loadLibrary("goodluck");      
  6. }      
  7. public native static int get();      
  8. public native static void set(int i);      
  9. public static void main(String[] args)      
  10. {      
  11. testdll test = new testdll();        
  12. test.set(10);       
  13. System.out.println(test.get());      
  14. }        
  15. }    
  16. public class testdll   
  17. {   
  18. static   
  19. {   
  20. System.loadLibrary("goodluck");   
  21. }   
  22. public native static int get();   
  23. public native static void set(int i);   
  24. public static void main(String[] args)   
  25. {   
  26. testdll test = new testdll();   
  27. test.set(10);   
  28. System.out.println(test.get());   
  29. }   

用Javac testdll.Java编译它,会生成testdll.class。

再用Javah testdll,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。

二、C/C++中所需要做的工作

对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现。然后编译连接成库文件即可。再把库文件拷贝到Java程序的路径下面,就可以用Java调用C/C++所实现的功能了。

接上例子。我们先看一下testdll.h文件的内容:

Java代码

  1. /* DO NOT EDIT THIS FILE - it is machine generated */      
  2. #include      
  3.     
  4. /* Header for class testdll */      
  5.     
  6. #ifndef _Included_testdll      
  7.     
  8. #define _Included_testdll      
  9.     
  10. #ifdef __cplusplus      
  11.     
  12. extern "C" {      
  13.     
  14. #endif      
  15.     
  16. /*     
  17.    
  18. * Class: testdll     
  19.    
  20. * Method: get     
  21.    
  22. * Signature: ()I     
  23.    
  24. */      
  25.     
  26. JNIEXPORT jint JNICALL Java_testdll_get      
  27.     
  28. (JNIEnv *, jclass);      
  29.     
  30. /*     
  31.    
  32. * Class: testdll     
  33.    
  34. * Method: set     
  35.    
  36. * Signature: (I)V     
  37.    
  38. */      
  39.     
  40. JNIEXPORT void JNICALL Java_testdll_set      
  41.     
  42. (JNIEnv *, jclass, jint);      
  43.     
  44. #ifdef __cplusplus      
  45.     
  46. }      
  47.     
  48. #endif      
  49.     
  50. #endif    
  51.  
  52. /* DO NOT EDIT THIS FILE - it is machine generated */   
  53. #include   
  54.  
  55. /* Header for class testdll */   
  56.  
  57. #ifndef _Included_testdll   
  58.  
  59. #define _Included_testdll   
  60.  
  61. #ifdef __cplusplus   
  62.  
  63. extern "C" {   
  64.  
  65. #endif   
  66.  
  67. /*   
  68.  
  69. * Class: testdll   
  70.  
  71. * Method: get   
  72.  
  73. * Signature: ()I   
  74.  
  75. */   
  76.  
  77. JNIEXPORT jint JNICALL Java_testdll_get   
  78.  
  79. (JNIEnv *, jclass);   
  80.  
  81. /*   
  82.  
  83. * Class: testdll   
  84.  
  85. * Method: set   
  86.  
  87. * Signature: (I)V   
  88.  
  89. */   
  90.  
  91. JNIEXPORT void JNICALL Java_testdll_set   
  92.  
  93. (JNIEnv *, jclass, jint);   
  94.  
  95. #ifdef __cplusplus   
  96.  
  97. }   
  98.  
  99. #endif   
  100.  
  101. #endif 

在具体实现的时候,我们只关心两个函数原型 :

Java代码

JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);  

JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);

和Java代码

JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);  

JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);

这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使Java的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是Java_再加上Java程序的package路径再加函数名组成的。参数中,我们也只需要关心在Java程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。

好,下面我们用testdll.cpp文件具体实现这两个函数:

Java代码

  1. #include "testdll.h"       
  2. int i = 0;       
  3. JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)       
  4. {       
  5. return i;       
  6. }       
  7. JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j)        
  8. {        
  9. i = j;        
  10. }    
  11. #include "testdll.h"   
  12. int i = 0;   
  13. JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)   
  14. {   
  15. return i;   
  16. }   
  17. JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j)   
  18. {   
  19. i = j;   

编译连接成库文件,本例是在WINDOWS下做的,生成的是DLL文件。并且名称要与Java中需要调用的一致,这里就是goodluck.dll

把goodluck.dll拷贝到testdll.class的目录下,Java testdll运行它,就可以观察到结果了。