27
java JNI 编编编编 JNI 编编编编编编编编编 一,一,,一西,一, JNI 1. 编编编编编编 Java 编编 编编 编 编 ,一, Java 编编编编编编 Sun 编编编 Java 编编编编编编编编 Java 编 编编 编 编 , 。, Java 编编编编编编 编编编编编编编编 ,, Java 编编 编编编编编编编编编编编编 。, JIT(Just In Time ) 编编编 编编编编编编编 。: Java 编编编编 Java 编编编编编编编编 Java 编编编编编编编编编编 JIT 编编编编 Java 编编编 。, 编编编编 编编编编编编编编 Java 编编编编编编 ,;,,。 JIT 编编 编 ,。 编编编编编编编编编 Java 编编编编 编编编编编编编 一。 Java 编编 Java 编编编编编编编编编编编编编编 Java 编编编 编编编编 Java 编编编编编编编编编编编编编编编 编编编编编编编编编编 (Windows 编编 . dll 编编编 Unix 编编 . so 编编 ) 编编 。, Java 编编编编编 JNI(Java Native Interface, Java 编编编编编 ) 编编 JNI 编编 Java 编编编编编编编编编 ,, 。 ,,。, 编 编编 Java 编编编编编编编编 Java 编编编 JDK 1. 2 编编FindClass 编编编编 。一, ; 编编 编编编编编编编编编编编 ,。, Java 编编编编编编编 C/C++ 编编 Java 2. 编编编编编编编编编编编编 JAVA 编编编编编编编编编编编编 编编编编编编编编 ,,,。 JAVA 编编编编编编编编编 JNI JAVA 编编 JNI 编编编 ,( WINDOWS 编编编编 DLL 编编 UNIX 编编编编 SO )。 JAVA ,。 3. 编编编编编编编 编编 ”编 一, Java 编编编编编编编编编编编 ,, SUN 编编编编编编 J2ME(Java 2 P1atform Micro Edition) 编编编编编编编 Java 编编 编编编编编编编编编编 ,,。 SUN 编编 Java 编编编 (JVM) 编编 Java 编编编编编编编编 Java 编编编编编编编编编编 JVM 编编 Java 编编编编编编 编编编编编编编编编编编编编编编 、,, 。 JNI 编编 JNI 编编编编编 编编编编编 ,一 JNI

Java JNI 编程进阶

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Java JNI 编程进阶

java JNI 编程进阶

JNI 一直以来都很少去关注,但却是我心中的一个结,最近这几天刚好手头有点时间,因此抽空看了一下这方面的东西,整理了一份文档,JNI 技术的出现主要是基于三个方面的应用需求:

 

1. 解决性能问题Java 具有平台无关性,这使人们在开发企业级应用的时候总是把它作为主要候选方案之一,但是性能方面的因素又大大削弱 了它的竞争力。为此,提高 Java 的性能就显得十分重要。Sun 公司及 Java 的支持者们为提高 Java 的运行速度已经做出了许多努力,其中大多数集中在 程序设计的方法和模式选择方面。由于算法和设计模式的优化是通用的,对 Java 有效的优化算法和设计模式,对其他编译语言也基本同样适用,因此不能从根本 上改变 Java 程序与编译型语言在执行效率方面的差异。由此,于是人们开始引入 JIT(Just In Time,及时编译)的概念。它的基本原理是:首先通过 Java 编译器把 Java 源代码编译成平台无关的二进制字节码。然后在 Java 程序真正执行之前, 系统通过 JIT 编译器把 Java 的字节码编译为本地化机器码。最后,系统执行本地化机器码,节省了对字节码进行解释的时间。这样做的优点是大大提高了 Java 程序的性能,缩短了加载程序的时间;同时,由于编译的结果并不在程序运行间保存,因此也节约了存储空间。缺点是由于 JIT 编译器对所有的代码都想 优化,因此同样也占用了很多时间。

 

动态优化技术是提高 Java 性能的另一个尝试。该技术试图通过把 Java 源程序直接编译成机器码,以充分利用 Java 动态编译和静态编译技术来提高 Java 的性能。该方法把输入的Java 源码或字节码转换为经过高度优化的可执行代码和动态库 (Windows 中的. dll 文件或Unix 中的. so 文件)。该技术能大大提高程序的性能,但却破坏了 Java 的可移植性。

JNI(Java Native Interface, Java 本地化方法)技术由此闪亮登场。因为采用 JNI 技术只是针对一些严重影响 Java 性能的代码段,该部分可能只占源程序的极少部分,所以几乎可以不 考虑该部分代码在主流平台之间移植的工作量。同时,也不必过分担心类型匹配问题,我们完全可以控制代码不出现这种错误。此外,也不必担心安全控制问题,因 为 Java安全模型已扩展为允许非系统类加载和调用本地方法。根据 Java规范,从 JDK 1. 2 开始,FindClass将设法找到与当前的本地方法关联的类加载器。如果平台相关代码属于一个系统类,则无需涉及任何类加载器; 否则,将调用适当的类加载器来加载和链接已命名的类。换句话说,如果在 Java 程序中直接调用 C/C++语言产生的机器码,该部分代码的安全性就由 Java虚拟机控制。

 

2. 解决本机平台接口调用问题JAVA 以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得 很少,约束了它的功能。解决 JAVA 对本地操作的一种方法就是

Page 2: Java JNI 编程进阶

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

 

3. 嵌入式开发应用“一次编程,到处使用”的 Java软件概念原本就是针对网上嵌入式小设备提出的,几经周折,目前 SUN 公司已推出了 J2ME(Java 2 P1atform Micro Edition)针对信息家电的 Java版本,其技术日趋成熟,开始投入使用。SUN 公司 Java虚拟机(JVM)技术的有序开放,使得Java软件真正 实现跨平台运行,即 Java 应用小程序能够在带有 JVM 的任何硬软件系统上执行。加上 Java 语言本身所具有的安全性、可靠性和可移植性等特点,对实现瘦 身上网的信息家电等网络设备十分有利,同时对嵌入式设备特别是上网设备软件编程技术产生了很大的影响。也正是由于 JNI 解决了本机平台接口调用问题,于是 JNI 在嵌入式开发领域也是如火如荼。

 

不失直观性,我们首先写一个 JNI小例子:

 

Java 代码

1. public class HelloJni {   2.     public native void displayHelloJni();   3.    4.     static {   5.         System.loadLibrary("helloJni");   6.     }   7.    8.     public static void main(String[] args) {   9.         //System.out.println(System.getProperty("java.library.path"));   10.         new HelloJni().displayHelloJni();   11.     }   12. }   public class HelloJni {13. public native void displayHelloJni();14.15. static {16. System.loadLibrary("helloJni");17. }18.19. public static void main(String[] args) {20.

//System.out.println(System.getProperty("java.library.path"));

21. new HelloJni().displayHelloJni();22. }23. }

Page 3: Java JNI 编程进阶

 

在 class 文件生成的相应目录执行命令如下:----------------------------------------------------E:\projects\jni\target\classes>javah HelloJni----------------------------------------------------

 

得到C++文件 HelloJni.h

Cpp 代码

1. /* DO NOT EDIT THIS FILE - it is machine generated */   2. #include <jni.h>   3. /* Header for class HelloJni */   4.    5. #ifndef _Included_HelloJni   6. #define _Included_HelloJni   7. #ifdef __cplusplus   8. extern "C" {   9. #endif   10. /*  11.  * Class:     HelloJni  12.  * Method:    displayHelloJni  13.  * Signature: ()V  14.  */   15. JNIEXPORT void JNICALL Java_HelloJni_displayHelloJni   16.   (JNIEnv *, jobject);   17.    18. #ifdef __cplusplus   19. }   20. #endif   21. #endif   /* DO NOT EDIT THIS FILE - it is machine

generated */22. #include <jni.h>23. /* Header for class HelloJni */24.25. #ifndef _Included_HelloJni26. #define _Included_HelloJni27. #ifdef __cplusplus28. extern "C" {29. #endif30. /*31. * Class: HelloJni32. * Method: displayHelloJni33. * Signature: ()V34. */35. JNIEXPORT void JNICALL Java_HelloJni_displayHelloJni36. (JNIEnv *, jobject);37.

Page 4: Java JNI 编程进阶

38. #ifdef __cplusplus39. }40. #endif41. #endif

 

JNI函数名称分为三部分:首先是 Java 关键字,供 Java虚拟机识别;然后是调用者类名称(全限定的类名,其中用下划线代替名称分隔符);最后是对应的方法名称,各段名称之间用下划线分割。

JNI函数的参数也由三部分组成:首先是 JNIEnv *,是一个指向 JNI 运行环境的指针;第二个参数随本地方法是静态还是非静态而有所不同一一非静态本地方法的第二个参数是对对象的引用,而静态本地方法的 第二个参数是对其 Java类的引用;其余的参数对应通常 Java 方法的参数,参数类型需要根据一定规则进行映射。

 

 

编写C++文件 HelloJni.h 的实现类,我是比较常用 VC6.0 来生成 dll 文件(helloJni.dll)的

Cpp 代码

1. #include <jni.h>   2. #include "HelloJni.h"   3. #include <stdio.h>   4.    5. JNIEXPORT void JNICALL    6. Java_HelloJni_displayHelloJni(JNIEnv *env, jobject obj)    7. {   8.     printf("Hello Dynamic Link Library has been calling!\n");   9.     printf("Java_HelloJni_displayHelloJni method has been executed!\n");   10.     return;   11. }   #include <jni.h>12. #include "HelloJni.h"13. #include <stdio.h>14.15. JNIEXPORT void JNICALL 16. Java_HelloJni_displayHelloJni(JNIEnv *env, jobject obj) 17. {18. printf("Hello Dynamic Link Library has been

calling!\n");19. printf("Java_HelloJni_displayHelloJni method has

been executed!\n");20. return;21. }

Page 5: Java JNI 编程进阶

 

其实此时,我们的工程目前还暂时不能生成我们想要的 helloJni.dll 文件,问题就出在了“#include <jni.h>”。由于 VC6.0里没有我们需要的“jni.h”文件,因此就需要手动加入到VC6.0 的环境中去。在 JAVA_HOME路 径下我们可以找到 include 文件夹,其中就可以找到我们需要的“jni.h”文件。为了避免以后麻烦起见,将所有的 C++文件全部拿出来,放在 “%CPP_HOME%\VC98\Include”路径下。然后将工程进行打包就可以得到我们需要的“helloJni.dll”文件了。

 

 将 helloJni.dll 文件放置于工程 classes目录,执行命令如下:-----------------------------------------------E:\projects\jni\target\classes>java HelloJni-----------------------------------------------

运行结果如下:-----------------------------------------------------------------Hello Dynamic Link Library has been calling!Java_HelloJni_displayHelloJni method has been executed!-----------------------------------------------------------------

但是要想在 eclipse 中运行 helloJni.dll 文件,就需要将文件拷贝到工程的根目录,或者将其放在诸如C:\WINDOWS \system32;C:\WINDOWS;等目录下。因为,eclipse 在运行helloJni.dll 文件时首先会去在当前根目录找,如果找不到则 在 path 上去找,因此你还可以为了方便管理生成的 dll 文件,将所有工程中的 dll 文件都放到一个特定的目录,然后将该目录加入到你的本地 path环境 变量中去,这样每次只需要将生成的 dll 文件放入 path目录下就可以访问了。注,如果需要加环境变量最好在加好以后重新启动一下 eclipse,确保 eclipse 能够加载到最新的 path环境。

 

接下来,对小例子进行重构:1. 新增一个基础类

 

Java 代码

1. package org.danlley.jni.test;   2.    3. public class BaseClass {   4.    5.     public BaseClass(String arg) {   6.         loadLibrary(arg);   7.     }  

Page 6: Java JNI 编程进阶

8.    9.     private static void loadLibrary(String arg) {   10.         System.loadLibrary(arg);   11.     }   12. }   package org.danlley.jni.test;13.14. public class BaseClass {15.16. public BaseClass(String arg) {17. loadLibrary(arg);18. }19.20. private static void loadLibrary(String arg) {21. System.loadLibrary(arg);22. }23. }

 

 2. 定义新类继承基础类

 

Java 代码

1. package org.danlley.jni.test;   2.    3. public class HelloJniTest extends BaseClass {   4.     public HelloJniTest(String arg){   5.         super(arg);   6.     }   7.     public native void displayHelloJni();   8. }   package org.danlley.jni.test;9.10. public class HelloJniTest extends BaseClass {11. public HelloJniTest(String arg){12. super(arg);13. }14. public native void displayHelloJni();15. }

 

3. 编写调用类

Java 代码

1. package org.danlley.jni.test;   2.    3. public class RunMain {   4.     public static void main(String[] args) {  

Page 7: Java JNI 编程进阶

5.         new HelloJniTest("helloJniTest").displayHelloJni();   6.     }   7. }   package org.danlley.jni.test;8.9. public class RunMain {10. public static void main(String[] args) {11. new

HelloJniTest("helloJniTest").displayHelloJni();12. }13. }

 此次,将 dll 文件定义为:helloJniTest.dll。

 

执行结果:------------------------------------------------------------------------------------Java_org_danlley_jni_test_HelloJniTest_displayHelloJni has been called!------------------------------------------------------------------------------------

 

例子相当简单,没有传入参数,也没有返回值,那么是不是可以让本地方法返回一些参数,同时又可以传入数据进行处理,并把处理结果返回给方法的调用者呢,先拿基本类型开刀。接下来对 HelloJniTest 继续进行改造:新增两个本地方法,如下:

Java 代码

1. package org.danlley.jni.test;   2.    3. public class HelloJniTest extends BaseClass {   4.     public HelloJniTest(String arg){   5.         super(arg);   6.     }   7.     public native void displayHelloJni();   8.        9.     public native int getDynamicIntDataNoParam();   10.        11.     public native int getDynamicIntData(int i);   12. }   package org.danlley.jni.test;13.14. public class HelloJniTest extends BaseClass {15. public HelloJniTest(String arg){16. super(arg);17. }18. public native void displayHelloJni();19. 20. public native int getDynamicIntDataNoParam();21. 22. public native int getDynamicIntData(int i);23. }

Page 8: Java JNI 编程进阶

 

重新生成 org_danlley_jni_test_HelloJniTest.h 文件,并改写其实现类org_danlley_jni_test_HelloJniTest.cpp如下:

Cpp 代码

1. // org_danlley_jni_test_HelloJniTest.cpp: implementation of the org_danlley_jni_test_HelloJniTest class.  

2. //   3. //////////////////////////////////////////////////////////////////////   4.    5. #include "org_danlley_jni_test_HelloJniTest.h"   6. #include <jni.h>   7. #include <stdio.h>   8.    9. JNIEXPORT void JNICALL    10. Java_org_danlley_jni_test_HelloJniTest_displayHelloJni(JNIEnv *env,

jobject obj)    11. {   12.     printf("Java_org_danlley_jni_test_HelloJniTest_displayHelloJni has

been called!\n");   13.     return;   14. }   15.    16. JNIEXPORT jint JNICALL    17. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam(

JNIEnv *env, jobject obj)    18. {   19.     return 65535;   20. }   21.    22. JNIEXPORT jint JNICALL    23. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData(JNIEnv

*env, jobject obj, jint i)   24. {   25.     i*=i;   26.     return i;   27. }   // org_danlley_jni_test_HelloJniTest.cpp:

implementation of the org_danlley_jni_test_HelloJniTest class.

28. //29. ////////////////////////////////////////////////////////

//////////////30.31. #include "org_danlley_jni_test_HelloJniTest.h"32. #include <jni.h>33. #include <stdio.h>34.35. JNIEXPORT void JNICALL

Page 9: Java JNI 编程进阶

36. Java_org_danlley_jni_test_HelloJniTest_displayHelloJni(JNIEnv *env, jobject obj)

37. {38.

printf("Java_org_danlley_jni_test_HelloJniTest_displayHelloJni has been called!\n");

39. return;40. }41.42. JNIEXPORT jint JNICALL 43. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData

NoParam(JNIEnv *env, jobject obj) 44. {45. return 65535;46. }47.48. JNIEXPORT jint JNICALL 49. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData

(JNIEnv *env, jobject obj, jint i)50. {51. i*=i;52. return i;53. }

 

修改 RunMain 类:

Java 代码

1. package org.danlley.jni.test;   2.    3. public class RunMain {   4.     public static void main(String[] args) {   5.         HelloJniTest tester=new HelloJniTest("helloJniTest");   6.         tester.displayHelloJni();   7.         int i=tester.getDynamicIntDataNoParam();   8.         System.out.println("tester.getDynamicIntDataNoParam()="+i);   9.         int j=tester.getDynamicIntData(100);   10.         System.out.println("tester.getDynamicIntData(100)="+j);   11.     }   12. }   package org.danlley.jni.test;13.14. public class RunMain {15. public static void main(String[] args) {16. HelloJniTest tester=new

HelloJniTest("helloJniTest");17. tester.displayHelloJni();18. int i=tester.getDynamicIntDataNoParam();19.

System.out.println("tester.getDynamicIntDataNoParam()="+i);20. int j=tester.getDynamicIntData(100);

Page 10: Java JNI 编程进阶

21. System.out.println("tester.getDynamicIntData(100)="+j);

22. }23. }

 

运行 RunMain:

-----------------------------------------------------------------------tester.getDynamicIntDataNoParam()=65535tester.getDynamicIntData(100)=10000Java_org_danlley_jni_test_HelloJniTest_displayHelloJni has been called!-----------------------------------------------------------------------

OK,一切正常。

 

还是不过瘾,简单对象可以处理了,如果是一个 java 对象,还可以处理吗,答案是当然可以,接下来我们来继续对 helloJniTest 类进行改造。新增一个方法如下:

Java 代码

1. package org.danlley.jni.test;   2.    3. public class HelloJniTest extends BaseClass {   4.     public HelloJniTest(String arg){   5.         super(arg);   6.     }   7.     public native void displayHelloJni();   8.        9.     public native int getDynamicIntDataNoParam();   10.        11.     public native int getDynamicIntData(int i);   12.        13.     public native String getDynamicStringData(String arg);   14. }   package org.danlley.jni.test;15.16. public class HelloJniTest extends BaseClass {17. public HelloJniTest(String arg){18. super(arg);19. }20. public native void displayHelloJni();21. 22. public native int getDynamicIntDataNoParam();23. 24. public native int getDynamicIntData(int i);25. 26. public native String getDynamicStringData(String

arg);

Page 11: Java JNI 编程进阶

27. }

 

重新生成 org_danlley_jni_test_HelloJniTest.h 文件:

Cpp 代码

1. /* DO NOT EDIT THIS FILE - it is machine generated */   2. #include <jni.h>   3. /* Header for class org_danlley_jni_test_HelloJniTest */   4.    5. #ifndef _Included_org_danlley_jni_test_HelloJniTest   6. #define _Included_org_danlley_jni_test_HelloJniTest   7. #ifdef __cplusplus   8. extern "C" {   9. #endif   10. /*  11.  * Class:     org_danlley_jni_test_HelloJniTest  12.  * Method:    displayHelloJni  13.  * Signature: ()V  14.  */   15. JNIEXPORT void JNICALL

Java_org_danlley_jni_test_HelloJniTest_displayHelloJni   16.   (JNIEnv *, jobject);   17.    18. /*  19.  * Class:     org_danlley_jni_test_HelloJniTest  20.  * Method:    getDynamicIntDataNoParam  21.  * Signature: ()I  22.  */   23. JNIEXPORT jint JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam   24.   (JNIEnv *, jobject);   25.    26. /*  27.  * Class:     org_danlley_jni_test_HelloJniTest  28.  * Method:    getDynamicIntData  29.  * Signature: (I)I  30.  */   31. JNIEXPORT jint JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData   32.   (JNIEnv *, jobject, jint);   33.    34. /*  35.  * Class:     org_danlley_jni_test_HelloJniTest  36.  * Method:    getDynamicStringData  37.  * Signature: (Ljava/lang/String;)Ljava/lang/String;  38.  */   39. JNIEXPORT jstring JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData  

Page 12: Java JNI 编程进阶

40.   (JNIEnv *, jobject, jstring);   41.    42. #ifdef __cplusplus   43. }   44. #endif   45. #endif   /* DO NOT EDIT THIS FILE - it is machine

generated */46. #include <jni.h>47. /* Header for class org_danlley_jni_test_HelloJniTest */48.49. #ifndef _Included_org_danlley_jni_test_HelloJniTest50. #define _Included_org_danlley_jni_test_HelloJniTest51. #ifdef __cplusplus52. extern "C" {53. #endif54. /*55. * Class: org_danlley_jni_test_HelloJniTest56. * Method: displayHelloJni57. * Signature: ()V58. */59. JNIEXPORT void JNICALL

Java_org_danlley_jni_test_HelloJniTest_displayHelloJni60. (JNIEnv *, jobject);61.62. /*63. * Class: org_danlley_jni_test_HelloJniTest64. * Method: getDynamicIntDataNoParam65. * Signature: ()I66. */67. JNIEXPORT jint JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam

68. (JNIEnv *, jobject);69.70. /*71. * Class: org_danlley_jni_test_HelloJniTest72. * Method: getDynamicIntData73. * Signature: (I)I74. */75. JNIEXPORT jint JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData76. (JNIEnv *, jobject, jint);77.78. /*79. * Class: org_danlley_jni_test_HelloJniTest80. * Method: getDynamicStringData81. * Signature: (Ljava/lang/String;)Ljava/lang/String;82. */83. JNIEXPORT jstring JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData84. (JNIEnv *, jobject, jstring);85.86. #ifdef __cplusplus

Page 13: Java JNI 编程进阶

87. }88. #endif89. #endif

 

改写 org_danlley_jni_test_HelloJniTest.cpp 文件:

Cpp 代码

1. // org_danlley_jni_test_HelloJniTest.cpp: implementation of the org_danlley_jni_test_HelloJniTest class.  

2. //   3. //////////////////////////////////////////////////////////////////////   4.    5. #include "org_danlley_jni_test_HelloJniTest.h"   6. #include <jni.h>   7. #include <stdio.h>   8.    9. JNIEXPORT void JNICALL    10. Java_org_danlley_jni_test_HelloJniTest_displayHelloJni(JNIEnv *env,

jobject obj)    11. {   12.     printf("Java_org_danlley_jni_test_HelloJniTest_displayHelloJni has

been called!\n");   13.     return;   14. }   15.    16. JNIEXPORT jint JNICALL    17. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam(

JNIEnv *env, jobject obj)    18. {   19.     return 65535;   20. }   21.    22. JNIEXPORT jint JNICALL    23. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData(JNIEnv

*env, jobject obj, jint i)   24. {   25.     i*=i;   26.     return i;   27. }   28.    29. JNIEXPORT jstring JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData   30. (JNIEnv *env, jobject obj, jstring arg){   31.     //Get the native string from javaString   32.     const char *nativeString = env->GetStringUTFChars(arg, 0);   33.     printf("%s", nativeString);   34.     //DON'T FORGET THIS LINE!!!   35.     env->ReleaseStringUTFChars(arg, nativeString);  

Page 14: Java JNI 编程进阶

36.     return arg;   37. }   // org_danlley_jni_test_HelloJniTest.cpp:

implementation of the org_danlley_jni_test_HelloJniTest class.

38. //39. ////////////////////////////////////////////////////////

//////////////40.41. #include "org_danlley_jni_test_HelloJniTest.h"42. #include <jni.h>43. #include <stdio.h>44.45. JNIEXPORT void JNICALL 46. Java_org_danlley_jni_test_HelloJniTest_displayHelloJni(J

NIEnv *env, jobject obj) 47. {48.

printf("Java_org_danlley_jni_test_HelloJniTest_displayHelloJni has been called!\n");

49. return;50. }51.52. JNIEXPORT jint JNICALL 53. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData

NoParam(JNIEnv *env, jobject obj) 54. {55. return 65535;56. }57.58. JNIEXPORT jint JNICALL 59. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData

(JNIEnv *env, jobject obj, jint i)60. {61. i*=i;62. return i;63. }64.65. JNIEXPORT jstring JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData66. (JNIEnv *env, jobject obj, jstring arg){67. //Get the native string from javaString68. const char *nativeString = env-

>GetStringUTFChars(arg, 0);69. printf("%s", nativeString);70. //DON'T FORGET THIS LINE!!!71. env->ReleaseStringUTFChars(arg, nativeString);72. return arg;73. }

  

 重新对 C++工程打包成 dll 文件,运行结果:---------------------------------------------------------------------------

Page 15: Java JNI 编程进阶

tester.getDynamicIntDataNoParam()=65535tester.getDynamicIntData(100)=10000tester.getDynamicStringData=My first String testJava_org_danlley_jni_test_HelloJniTest_displayHelloJni has been called!My first String test---------------------------------------------------------------------------

我们不仅把 Java 的一个 String 对象成功的传给了 dll,而且还将处理后的结果返回了出来。

 

但是总觉得还是不够,那我们就再来个比较复杂的对象把,我们这次将一个整形数组通过java传给 dll,看看是不是也可以处理,继续还是对 helloJniTest 类进行改造,新增一个方法:

Java 代码

1. package org.danlley.jni.test;   2.    3. public class HelloJniTest extends BaseClass {   4.     public HelloJniTest(String arg){   5.         super(arg);   6.     }   7.     public native void displayHelloJni();   8.        9.     public native int getDynamicIntDataNoParam();   10.        11.     public native int getDynamicIntData(int i);   12.        13.     public native String getDynamicStringData(String arg);   14.        15.     public native int[] getDynamicArrayData(int[] args);   16. }   package org.danlley.jni.test;17.18. public class HelloJniTest extends BaseClass {19. public HelloJniTest(String arg){20. super(arg);21. }22. public native void displayHelloJni();23. 24. public native int getDynamicIntDataNoParam();25. 26. public native int getDynamicIntData(int i);27. 28. public native String getDynamicStringData(String

arg);29. 30. public native int[] getDynamicArrayData(int[] args);31. }

Page 16: Java JNI 编程进阶

 

重新生成 org_danlley_jni_test_HelloJniTest.h 文件

Cpp 代码

1. /* DO NOT EDIT THIS FILE - it is machine generated */   2. #include <jni.h>   3. /* Header for class org_danlley_jni_test_HelloJniTest */   4.    5. #ifndef _Included_org_danlley_jni_test_HelloJniTest   6. #define _Included_org_danlley_jni_test_HelloJniTest   7. #ifdef __cplusplus   8. extern "C" {   9. #endif   10. /*  11.  * Class:     org_danlley_jni_test_HelloJniTest  12.  * Method:    displayHelloJni  13.  * Signature: ()V  14.  */   15. JNIEXPORT void JNICALL

Java_org_danlley_jni_test_HelloJniTest_displayHelloJni   16.   (JNIEnv *, jobject);   17.    18. /*  19.  * Class:     org_danlley_jni_test_HelloJniTest  20.  * Method:    getDynamicIntDataNoParam  21.  * Signature: ()I  22.  */   23. JNIEXPORT jint JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam   24.   (JNIEnv *, jobject);   25.    26. /*  27.  * Class:     org_danlley_jni_test_HelloJniTest  28.  * Method:    getDynamicIntData  29.  * Signature: (I)I  30.  */   31. JNIEXPORT jint JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData   32.   (JNIEnv *, jobject, jint);   33.    34. /*  35.  * Class:     org_danlley_jni_test_HelloJniTest  36.  * Method:    getDynamicStringData  37.  * Signature: (Ljava/lang/String;)Ljava/lang/String;  38.  */   39. JNIEXPORT jstring JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData   40.   (JNIEnv *, jobject, jstring);   41.   

Page 17: Java JNI 编程进阶

42. /*  43.  * Class:     org_danlley_jni_test_HelloJniTest  44.  * Method:    getDynamicArrayData  45.  * Signature: ([I)[I  46.  */   47. JNIEXPORT jintArray JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicArrayData   48.   (JNIEnv *, jobject, jintArray);   49.    50. #ifdef __cplusplus   51. }   52. #endif   53. #endif   /* DO NOT EDIT THIS FILE - it is machine

generated */54. #include <jni.h>55. /* Header for class org_danlley_jni_test_HelloJniTest */56.57. #ifndef _Included_org_danlley_jni_test_HelloJniTest58. #define _Included_org_danlley_jni_test_HelloJniTest59. #ifdef __cplusplus60. extern "C" {61. #endif62. /*63. * Class: org_danlley_jni_test_HelloJniTest64. * Method: displayHelloJni65. * Signature: ()V66. */67. JNIEXPORT void JNICALL

Java_org_danlley_jni_test_HelloJniTest_displayHelloJni68. (JNIEnv *, jobject);69.70. /*71. * Class: org_danlley_jni_test_HelloJniTest72. * Method: getDynamicIntDataNoParam73. * Signature: ()I74. */75. JNIEXPORT jint JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam

76. (JNIEnv *, jobject);77.78. /*79. * Class: org_danlley_jni_test_HelloJniTest80. * Method: getDynamicIntData81. * Signature: (I)I82. */83. JNIEXPORT jint JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData84. (JNIEnv *, jobject, jint);85.86. /*87. * Class: org_danlley_jni_test_HelloJniTest88. * Method: getDynamicStringData

Page 18: Java JNI 编程进阶

89. * Signature: (Ljava/lang/String;)Ljava/lang/String;90. */91. JNIEXPORT jstring JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData92. (JNIEnv *, jobject, jstring);93.94. /*95. * Class: org_danlley_jni_test_HelloJniTest96. * Method: getDynamicArrayData97. * Signature: ([I)[I98. */99. JNIEXPORT jintArray JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicArrayData100. (JNIEnv *, jobject, jintArray);101.102. #ifdef __cplusplus103. }104. #endif105. #endif

 

改写 org_danlley_jni_test_HelloJniTest.cpp 文件:

Cpp 代码

1. // org_danlley_jni_test_HelloJniTest.cpp: implementation of the org_danlley_jni_test_HelloJniTest class.  

2. //   3. //////////////////////////////////////////////////////////////////////   4.    5. #include "org_danlley_jni_test_HelloJniTest.h"   6. #include <jni.h>   7. #include <stdio.h>   8.    9. JNIEXPORT void JNICALL    10. Java_org_danlley_jni_test_HelloJniTest_displayHelloJni(JNIEnv *env,

jobject obj)    11. {   12.     printf("Java_org_danlley_jni_test_HelloJniTest_displayHelloJni has

been called!\n");   13.     return;   14. }   15.    16. JNIEXPORT jint JNICALL    17. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam(

JNIEnv *env, jobject obj)    18. {   19.     return 65535;   20. }   21.    22. JNIEXPORT jint JNICALL   

Page 19: Java JNI 编程进阶

23. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData(JNIEnv *env, jobject obj, jint i)  

24. {   25.     i*=i;   26.     return i;   27. }   28.    29. JNIEXPORT jstring JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData   30. (JNIEnv *env, jobject obj, jstring arg){   31.     //Get the native string from javaString   32.     const char *nativeString = env->GetStringUTFChars(arg, 0);   33.     printf("%s", nativeString);   34.     //DON'T FORGET THIS LINE!!!   35.     env->ReleaseStringUTFChars(arg, nativeString);   36.     return arg;   37. }   38.    39.    40. JNIEXPORT jintArray JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicArrayData   41. (JNIEnv *env, jobject  obj, jintArray args){   42.     jint buf[10];   43.     jint i;   44.     env->GetIntArrayRegion(args, 0, 10, buf);   45.     jint j=0;   46.     for (i = 0; i < 10; i++) {   47.         j=buf[i];   48.         j*=j;   49.         buf[i]=j;   50.     }   51.     env->SetIntArrayRegion(args, 0, 10, buf);   52.     return args;   53. }   // org_danlley_jni_test_HelloJniTest.cpp:

implementation of the org_danlley_jni_test_HelloJniTest class.

54. //55. ////////////////////////////////////////////////////////

//////////////56.57. #include "org_danlley_jni_test_HelloJniTest.h"58. #include <jni.h>59. #include <stdio.h>60.61. JNIEXPORT void JNICALL 62. Java_org_danlley_jni_test_HelloJniTest_displayHelloJni(J

NIEnv *env, jobject obj) 63. {64.

printf("Java_org_danlley_jni_test_HelloJniTest_displayHelloJni has been called!\n");

65. return;

Page 20: Java JNI 编程进阶

66. }67.68. JNIEXPORT jint JNICALL 69. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData

NoParam(JNIEnv *env, jobject obj) 70. {71. return 65535;72. }73.74. JNIEXPORT jint JNICALL 75. Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData

(JNIEnv *env, jobject obj, jint i)76. {77. i*=i;78. return i;79. }80.81. JNIEXPORT jstring JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData82. (JNIEnv *env, jobject obj, jstring arg){83. //Get the native string from javaString84. const char *nativeString = env-

>GetStringUTFChars(arg, 0);85. printf("%s", nativeString);86. //DON'T FORGET THIS LINE!!!87. env->ReleaseStringUTFChars(arg, nativeString);88. return arg;89. }90.91.92. JNIEXPORT jintArray JNICALL

Java_org_danlley_jni_test_HelloJniTest_getDynamicArrayData93. (JNIEnv *env, jobject obj, jintArray args){94. jint buf[10];95. jint i;96. env->GetIntArrayRegion(args, 0, 10, buf);97. jint j=0;98. for (i = 0; i < 10; i++) {99. j=buf[i];100. j*=j;101. buf[i]=j;102. }103. env->SetIntArrayRegion(args, 0, 10, buf);104. return args;105. }

 

改写RunMain:

Java 代码

Page 21: Java JNI 编程进阶

1. package org.danlley.jni.test;   2.    3. public class RunMain {   4.     public static void main(String[] args) {   5.         HelloJniTest tester = new HelloJniTest("helloJniTest");   6.         tester.displayHelloJni();   7.         int i = tester.getDynamicIntDataNoParam();   8.         System.out.println("tester.getDynamicIntDataNoParam()=" + i);   9.         int j = tester.getDynamicIntData(100);   10.         System.out.println("tester.getDynamicIntData(100)=" + j);   11.         String str = tester.getDynamicStringData("My first String

test");   12.         System.out.println("tester.getDynamicStringData=" + str);   13.         int[] args_int = new int[10];   14.         for (int ii = 0; ii < 10; ii++) {   15.             args_int[ii] = ii;   16.         }   17.         int[] args_arr = tester.getDynamicArrayData(args_int);   18.         for (int ii = 0; ii < 10; ii++) {   19.             System.out.println(args_arr[ii]);   20.         }   21.     }   22. }   package org.danlley.jni.test;23.24. public class RunMain {25. public static void main(String[] args) {26. HelloJniTest tester = new

HelloJniTest("helloJniTest");27. tester.displayHelloJni();28. int i = tester.getDynamicIntDataNoParam();29.

System.out.println("tester.getDynamicIntDataNoParam()=" + i);30. int j = tester.getDynamicIntData(100);31.

System.out.println("tester.getDynamicIntData(100)=" + j);32. String str = tester.getDynamicStringData("My

first String test");33.

System.out.println("tester.getDynamicStringData=" + str);34. int[] args_int = new int[10];35. for (int ii = 0; ii < 10; ii++) {36. args_int[ii] = ii;37. }38. int[] args_arr =

tester.getDynamicArrayData(args_int);39. for (int ii = 0; ii < 10; ii++) {40. System.out.println(args_arr[ii]);41. }42. }43. }

 

Page 22: Java JNI 编程进阶

运行结果:--------------------------------------------------------------------------------tester.getDynamicIntDataNoParam()=65535tester.getDynamicIntData(100)=10000tester.getDynamicStringData=My first String test0149162536496481Java_org_danlley_jni_test_HelloJniTest_displayHelloJni has been called!My first String test--------------------------------------------------------------------------------

 

 

 

  

参考资料:

http://en.wikipedia.org/wiki/Java_Native_Interfacehttp://www.yesky.com/20011004/199789.shtmlhttp://www.21ic.com/news/html/63/show13260.htmhttp://java.ccidnet.com/art/297/20060228/439729_1.htmlhttp://www.blogjava.net/soft/archive/2006/11/13/posoft.htmlhttp://www.blogjava.net/soft/archive/2006/11/13/80788.htmlhttp://www.blogjava.net/soft/archive/2006/11/13/80789.html