狠狠撸

狠狠撸Share a Scribd company logo
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 代码

  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.p
     ath"));
  21.           new HelloJni().displayHelloJni();
  22.      }
  23.}
在 class 文件生成的相应目录执行命令如下:
----------------------------------------------------
E:projectsjnitargetclasses>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_HelloJni
   26.#define _Included_HelloJni
   27.#ifdef __cplusplus
   28.extern "C" {
   29.#endif
   30./*
   31. * Class:         HelloJni
   32. * Method:        displayHelloJni
   33. * Signature: ()V
   34. */
   35.JNIEXPORT void JNICALL Java_HelloJni_displayHelloJni
   36. (JNIEnv *, jobject);
37.
  38.#ifdef __cplusplus
  39.}
  40.#endif
  41.#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.}



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



 将 helloJni.dll 文件放置于工程 classes 目录,执行命令如下:
-----------------------------------------------
E:projectsjnitargetclasses>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.   }
  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) {
   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.}



重新生成 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(JNIEn
     v *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
  36.Java_org_danlley_jni_test_HelloJniTest_displayHelloJni(JNIEnv
    *env, jobject obj)
  37.{
  38.    printf("Java_org_danlley_jni_test_HelloJniTest_displayHello
    Jni has been called!n");
  39.    return;
  40.}
  41.
  42.JNIEXPORT jint JNICALL
  43.Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam
    (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);
  21.          System.out.println("tester.getDynamicIntData(100)="+j);
  22.     }
  23.}



运行 RunMain:

-----------------------------------------------------------------------
tester.getDynamicIntDataNoParam()=65535
tester.getDynamicIntData(100)=10000
Java_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);
  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
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_HelloJniTest
50.#define _Included_org_danlley_jni_test_HelloJniTest
51.#ifdef __cplusplus
52.extern "C" {
53.#endif
54./*
55. * Class:         org_danlley_jni_test_HelloJniTest
56. * Method:        displayHelloJni
57. * Signature: ()V
58. */
59.JNIEXPORT void JNICALL
   Java_org_danlley_jni_test_HelloJniTest_displayHelloJni
60. (JNIEnv *, jobject);
61.
62./*
63. * Class:         org_danlley_jni_test_HelloJniTest
64. * Method:        getDynamicIntDataNoParam
65. * Signature: ()I
66. */
67.JNIEXPORT jint JNICALL
    Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam
  68. (JNIEnv *, jobject);
  69.
  70./*
  71. * Class:     org_danlley_jni_test_HelloJniTest
  72. * Method:    getDynamicIntData
  73. * Signature: (I)I
  74. */
  75.JNIEXPORT jint JNICALL
    Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData
  76. (JNIEnv *, jobject, jint);
  77.
  78./*
  79. * Class:     org_danlley_jni_test_HelloJniTest
  80. * Method:    getDynamicStringData
  81. * Signature: (Ljava/lang/String;)Ljava/lang/String;
  82. */
  83.JNIEXPORT jstring JNICALL
    Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData
  84. (JNIEnv *, jobject, jstring);
  85.
  86.#ifdef __cplusplus
  87.}
  88.#endif
  89.#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(JNIEn
   v *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);
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(JNIEnv
   *env, jobject obj)
47.{
48.     printf("Java_org_danlley_jni_test_HelloJniTest_displayHello
   Jni has been called!n");
49.     return;
50.}
51.
52.JNIEXPORT jint JNICALL
53.Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam
     (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_getDynamicStringData
   66.(JNIEnv *env, jobject obj, jstring arg){
   67.     //Get the native string from javaString
   68.    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 文件,运行结果:
---------------------------------------------------------------------------
tester.getDynamicIntDataNoParam()=65535
tester.getDynamicIntData(100)=10000
tester.getDynamicStringData=My first String test
Java_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.}



重新生成 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.
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_HelloJniTest
58.#define _Included_org_danlley_jni_test_HelloJniTest
59.#ifdef __cplusplus
60.extern "C" {
61.#endif
62./*
63. * Class:     org_danlley_jni_test_HelloJniTest
64. * Method:    displayHelloJni
65. * Signature: ()V
66. */
67.JNIEXPORT void JNICALL
  Java_org_danlley_jni_test_HelloJniTest_displayHelloJni
68. (JNIEnv *, jobject);
69.
70./*
71. * Class:     org_danlley_jni_test_HelloJniTest
72. * Method:    getDynamicIntDataNoParam
73. * Signature: ()I
74. */
75.JNIEXPORT jint JNICALL
  Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam
76. (JNIEnv *, jobject);
77.
78./*
79. * Class:     org_danlley_jni_test_HelloJniTest
80. * Method:    getDynamicIntData
81. * Signature: (I)I
82. */
83.JNIEXPORT jint JNICALL
  Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData
84. (JNIEnv *, jobject, jint);
85.
86./*
87. * Class:     org_danlley_jni_test_HelloJniTest
88. * Method:    getDynamicStringData
89. * Signature: (Ljava/lang/String;)Ljava/lang/String;
90. */
91.JNIEXPORT jstring JNICALL
  Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData
92. (JNIEnv *, jobject, jstring);
93.
94./*
95. * Class:     org_danlley_jni_test_HelloJniTest
96. * Method:    getDynamicArrayData
97. * Signature: ([I)[I
98. */
99.JNIEXPORT jintArray JNICALL
    Java_org_danlley_jni_test_HelloJniTest_getDynamicArrayData
  100. (JNIEnv *, jobject, jintArray);
  101.
  102.#ifdef __cplusplus
  103.}
  104.#endif
  105.#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(JNIEn
     v *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);
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(JNIEnv
   *env, jobject obj)
63.{
64.     printf("Java_org_danlley_jni_test_HelloJniTest_displayHello
   Jni has been called!n");
65.     return;
66.}
67.
68.JNIEXPORT jint JNICALL
69.Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam
    (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_getDynamicStringData
  82.(JNIEnv *env, jobject obj, jstring arg){
  83.     //Get the native string from javaString
  84.    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_getDynamicArrayData
  93.(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 代码

  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.}
运行结果:
--------------------------------------------------------------------------------
tester.getDynamicIntDataNoParam()=65535
tester.getDynamicIntData(100)=10000
tester.getDynamicStringData=My first String test
0
1
4
9
16
25
36
49
64
81
Java_org_danlley_jni_test_HelloJniTest_displayHelloJni has been called!
My first String test
--------------------------------------------------------------------------------




参考资料:

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

More Related Content

Java JNI 编程进阶

  • 1. 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 可以实现和本地机器的紧密联系, 调用系统级的各接口方法。
  • 2. 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.p ath")); 21. new HelloJni().displayHelloJni(); 22. } 23.}
  • 3. 在 class 文件生成的相应目录执行命令如下: ---------------------------------------------------- E:projectsjnitargetclasses>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_HelloJni 26.#define _Included_HelloJni 27.#ifdef __cplusplus 28.extern "C" { 29.#endif 30./* 31. * Class: HelloJni 32. * Method: displayHelloJni 33. * Signature: ()V 34. */ 35.JNIEXPORT void JNICALL Java_HelloJni_displayHelloJni 36. (JNIEnv *, jobject);
  • 4. 37. 38.#ifdef __cplusplus 39.} 40.#endif 41.#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;
  • 5. 21.} 其实此时,我们的工程目前还暂时不能生成我们想要的 helloJni.dll 文件,问题就出在 了“#include <jni.h>”。由于 VC6.0 里没有我们需要的“jni.h”文件,因此就需要手动加入到 VC6.0 的环境中去。在 JAVA_HOME 路 径下我们可以找到 include 文件夹,其中就可以找到 我们需要的“jni.h”文件。为了避免以后麻烦起见,将所有的 C++文件全部拿出来,放在 “%CPP_HOME%VC98Include”路径下。然后将工程进行打包就可以得到我们需要 的“helloJni.dll”文件了。 将 helloJni.dll 文件放置于工程 classes 目录,执行命令如下: ----------------------------------------------- E:projectsjnitargetclasses>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. 6. loadLibrary(arg); 7. } 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 代码
  • 7. 1. package org.danlley.jni.test; 2. 3. public class RunMain { 4. public static void main(String[] args) { 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);
  • 8. 17. } 18. public native void displayHelloJni(); 19. 20. public native int getDynamicIntDataNoParam(); 21. 22. public native int getDynamicIntData(int i); 23.} 重新生成 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(JNIEn v *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;
  • 9. 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 36.Java_org_danlley_jni_test_HelloJniTest_displayHelloJni(JNIEnv *env, jobject obj) 37.{ 38. printf("Java_org_danlley_jni_test_HelloJniTest_displayHello Jni has been called!n"); 39. return; 40.} 41. 42.JNIEXPORT jint JNICALL 43.Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam (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);
  • 10. 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); 21. System.out.println("tester.getDynamicIntData(100)="+j); 22. } 23.} 运行 RunMain: ----------------------------------------------------------------------- tester.getDynamicIntDataNoParam()=65535 tester.getDynamicIntData(100)=10000 Java_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);
  • 11. 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); 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. */
  • 12. 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. 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_HelloJniTest 50.#define _Included_org_danlley_jni_test_HelloJniTest 51.#ifdef __cplusplus 52.extern "C" { 53.#endif 54./* 55. * Class: org_danlley_jni_test_HelloJniTest 56. * Method: displayHelloJni 57. * Signature: ()V 58. */ 59.JNIEXPORT void JNICALL Java_org_danlley_jni_test_HelloJniTest_displayHelloJni 60. (JNIEnv *, jobject); 61. 62./* 63. * Class: org_danlley_jni_test_HelloJniTest 64. * Method: getDynamicIntDataNoParam 65. * Signature: ()I 66. */
  • 13. 67.JNIEXPORT jint JNICALL Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam 68. (JNIEnv *, jobject); 69. 70./* 71. * Class: org_danlley_jni_test_HelloJniTest 72. * Method: getDynamicIntData 73. * Signature: (I)I 74. */ 75.JNIEXPORT jint JNICALL Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData 76. (JNIEnv *, jobject, jint); 77. 78./* 79. * Class: org_danlley_jni_test_HelloJniTest 80. * Method: getDynamicStringData 81. * Signature: (Ljava/lang/String;)Ljava/lang/String; 82. */ 83.JNIEXPORT jstring JNICALL Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData 84. (JNIEnv *, jobject, jstring); 85. 86.#ifdef __cplusplus 87.} 88.#endif 89.#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");
  • 14. 13. return; 14.} 15. 16.JNIEXPORT jint JNICALL 17.Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam(JNIEn v *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); 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(JNIEnv *env, jobject obj) 47.{ 48. printf("Java_org_danlley_jni_test_HelloJniTest_displayHello Jni has been called!n"); 49. return; 50.} 51. 52.JNIEXPORT jint JNICALL
  • 15. 53.Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam (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_getDynamicStringData 66.(JNIEnv *env, jobject obj, jstring arg){ 67. //Get the native string from javaString 68. 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 文件,运行结果: --------------------------------------------------------------------------- tester.getDynamicIntDataNoParam()=65535 tester.getDynamicIntData(100)=10000 tester.getDynamicStringData=My first String test Java_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 {
  • 16. 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.} 重新生成 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
  • 17. 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. 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 */
  • 18. 54.#include <jni.h> 55./* Header for class org_danlley_jni_test_HelloJniTest */ 56. 57.#ifndef _Included_org_danlley_jni_test_HelloJniTest 58.#define _Included_org_danlley_jni_test_HelloJniTest 59.#ifdef __cplusplus 60.extern "C" { 61.#endif 62./* 63. * Class: org_danlley_jni_test_HelloJniTest 64. * Method: displayHelloJni 65. * Signature: ()V 66. */ 67.JNIEXPORT void JNICALL Java_org_danlley_jni_test_HelloJniTest_displayHelloJni 68. (JNIEnv *, jobject); 69. 70./* 71. * Class: org_danlley_jni_test_HelloJniTest 72. * Method: getDynamicIntDataNoParam 73. * Signature: ()I 74. */ 75.JNIEXPORT jint JNICALL Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam 76. (JNIEnv *, jobject); 77. 78./* 79. * Class: org_danlley_jni_test_HelloJniTest 80. * Method: getDynamicIntData 81. * Signature: (I)I 82. */ 83.JNIEXPORT jint JNICALL Java_org_danlley_jni_test_HelloJniTest_getDynamicIntData 84. (JNIEnv *, jobject, jint); 85. 86./* 87. * Class: org_danlley_jni_test_HelloJniTest 88. * Method: getDynamicStringData 89. * Signature: (Ljava/lang/String;)Ljava/lang/String; 90. */ 91.JNIEXPORT jstring JNICALL Java_org_danlley_jni_test_HelloJniTest_getDynamicStringData 92. (JNIEnv *, jobject, jstring); 93. 94./* 95. * Class: org_danlley_jni_test_HelloJniTest 96. * Method: getDynamicArrayData 97. * Signature: ([I)[I 98. */
  • 19. 99.JNIEXPORT jintArray JNICALL Java_org_danlley_jni_test_HelloJniTest_getDynamicArrayData 100. (JNIEnv *, jobject, jintArray); 101. 102.#ifdef __cplusplus 103.} 104.#endif 105.#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(JNIEn v *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.}
  • 20. 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(JNIEnv *env, jobject obj) 63.{ 64. printf("Java_org_danlley_jni_test_HelloJniTest_displayHello Jni has been called!n"); 65. return; 66.} 67. 68.JNIEXPORT jint JNICALL
  • 21. 69.Java_org_danlley_jni_test_HelloJniTest_getDynamicIntDataNoParam (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_getDynamicStringData 82.(JNIEnv *env, jobject obj, jstring arg){ 83. //Get the native string from javaString 84. 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_getDynamicArrayData 93.(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 代码 1. package org.danlley.jni.test;
  • 22. 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.}
  • 23. 运行结果: -------------------------------------------------------------------------------- tester.getDynamicIntDataNoParam()=65535 tester.getDynamicIntData(100)=10000 tester.getDynamicStringData=My first String test 0 1 4 9 16 25 36 49 64 81 Java_org_danlley_jni_test_HelloJniTest_displayHelloJni has been called! My first String test -------------------------------------------------------------------------------- 参考资料: http://en.wikipedia.org/wiki/Java_Native_Interface http://www.yesky.com/20011004/199789.shtml http://www.21ic.com/news/html/63/show13260.htm http://java.ccidnet.com/art/297/20060228/439729_1.html http://www.blogjava.net/soft/archive/2006/11/13/posoft.html http://www.blogjava.net/soft/archive/2006/11/13/80788.html http://www.blogjava.net/soft/archive/2006/11/13/80789.html