Android中JNI的使用之一:Java原生JNI的使用、javah指令的使用以及图解教材

Java Nativie Interface(JNI,中文名称Java本地接口)标准时Java平台的一部分,它允许Java代码和其他语言写得代码进行交互。JNI是本地编程接口,它使得Java虚拟机(VM)内部运行的Java代码能够用其他编程语言(如C、C++和汇编语言)编写的应用程序和库进行交互操作。JNI的主要用途是为了对硬件进行访问以及追求高效率或可重用C/C++库。

    Android系统中采用了JNI的方式来调用C/C++方法,然而,在Android系统里进一步加强了Java JNI的使用,使JNI的调用更具有效率。因此,总的来说,Android系统里可以采用两种方式来使用JNI。第一种:Java原生JNI,使用dll等动态链接库 ;第二种,Android加强版JNI,通过动态加载*.so链接库来进行JNI调用。今天,我们分析第一种JNI使用方式,也称得上是JNI入门。

       由于Java与其他编程语言采用的语法不同,为了让Java与C/C++库函数能进行通信,约定的一个参数类型映射如下:

                Java类型              C/C++类型

                 void                       void

                 jboolean                boolean

                 jint                         int

                 jlong                      long

                 jdouble                  double

                 jfloat                      float

                 jbyte                      jbyte

                 jchar                     char

                 jshort                     shor

       上面的只是简单类型的一个映射,后面我们会完善其他参数类型的映射。

      

       开发环境介绍(Windows下):

            Eclipse:                   主要用来创建Java工程

            MicrosoftVC++6.0:  生成动态链接库供相应的Java文件加载

 

一、使用Eclipse创建Java工程

        本例中,我们简单的创建了一个Java工程HelloBabyJNI,工程绝对路径位于E:\MyCode\AndroidCode\HelloBabyJNI路径下, 主文件路径位于\src\lover\hellojni路径下(路径对后面的javah编译很重要)

         HelloBabyJNI.java文件如下:

           

  1. package com.lover.hellojni; 
  2.  
  3. /**
  4. * 一个简单的Java JNI实例
  5. *
  6. */ 
  7. publicclass HelloBabyJNI { 
  8.  
  9.     /*
  10.      * 静态构造函数,动态加载HelloBabyJNI动态库,其dll文件名为:HelloBabyJNI.dll --->由MSVC6.0软件创建
  11.      */ 
  12.     static
  13.         System.load("E:/HelloBabyJNI.dll");  // 可能需要 dll链接库的绝对存放路径  
  14.     } 
  15.  
  16.     /*
  17.      * 在Java中注册需要调用的C/C++本地方法(native method),也就是需要C/C++来实现的方法
  18.      */ 
  19.     publicnativeint add(int a, int b); 
  20.  
  21.     // main方法,加载动态库来调用C/C++本地方法  
  22.     publicstaticvoid main(String[] args) { 
  23.         HelloBabyJNI helloBabyJNI = new HelloBabyJNI(); 
  24.         // 调用注册的add方法来得到返回值  
  25.         int result = helloBabyJNI.add(2, 3); 
  26.         // 输出  
  27.         System.out.println("after invoke the native method,the result is "+ result); 
  28.     } 
package com.lover.hellojni;

/**
 * 一个简单的Java JNI实例
 * 
 */
public class HelloBabyJNI {

	/*
	 * 静态构造函数,动态加载HelloBabyJNI动态库,其dll文件名为:HelloBabyJNI.dll --->由MSVC6.0软件创建
	 */
	static {
		System.load("E:/HelloBabyJNI.dll");  // 可能需要 dll链接库的绝对存放路径
	}

	/*
	 * 在Java中注册需要调用的C/C++本地方法(native method),也就是需要C/C++来实现的方法
	 */
	public native int add(int a, int b);

	// main方法,加载动态库来调用C/C++本地方法
	public static void main(String[] args) {
		HelloBabyJNI helloBabyJNI = new HelloBabyJNI();
		// 调用注册的add方法来得到返回值
		int result = helloBabyJNI.add(2, 3);
		// 输出
		System.out.println("after invoke the native method,the result is "+ result);
	}
}

 

    

     2,编译HelloBabyJNI.java文件,生成HelloBabyJNI.class文件,位于路径\src\lover\hellojni\HelloBabyJNI.class

   

       3,使用javah指令编译HelloBabyJNI.class文件,生成Java与C/C++之间进行通信的约定接口,它规定了Java中nativemethod在C/C++的具体接口。运行cmd后,进入于E:\MyCode\AndroidCode\HelloBabyJNI\src路径下,使用javah指令,指令集形式如下:

        javah  -classpath   E:\MyCode\AndroidCode\HelloBabyJNI\src -jni  com.lover.hellojni.HelloBabyJNI,具体指令用法可以参考javah –help,本文只是重应用上。

           如图所示:

               

      

       成功运行后,我们可以在src文件夹下找到com_lover_hellojni_HelloBabyJNI.h文件,这个文件就是我们需要找到的约定接口,它  的命名规范为 包名_Java文件名。为了可理解性,我们将其重命名为HelloBabyJNI.h文件,内容如下:               

  1. /* DO NOT EDIT THIS FILE - it is machine generated */ 
  2. #include <jni.h>  
  3. /* Header for class com_lover_hellojni_HelloBabyJNI */ 
  4.  
  5. #ifndef _Included_com_lover_hellojni_HelloBabyJNI  
  6. #define _Included_com_lover_hellojni_HelloBabyJNI  
  7. #ifdef __cplusplus  
  8. extern"C"
  9. #endif  
  10. /*
  11. * Class:     com_lover_hellojni_HelloBabyJNI
  12. * Method:    add
  13. * Signature: (II)I
  14. */ 
  15. /*
  16. * java native method通过javah指令生成的约定接口
  17. */ 
  18. JNIEXPORT jint JNICALL Java_com_lover_hellojni_HelloBabyJNI_add 
  19.   (JNIEnv *, jobject, jint, jint); 
  20.  
  21. #ifdef __cplusplus  
  22. #endif  
  23. #endif 
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lover_hellojni_HelloBabyJNI */

#ifndef _Included_com_lover_hellojni_HelloBabyJNI
#define _Included_com_lover_hellojni_HelloBabyJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_lover_hellojni_HelloBabyJNI
 * Method:    add
 * Signature: (II)I
 */
/*
 * java native method通过javah指令生成的约定接口
 *  
 */
JNIEXPORT jint JNICALL Java_com_lover_hellojni_HelloBabyJNI_add
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

 

     PS:1, 由于-jni指令在javah中是默认选项,因此我们可以忽略掉它

            2,在Dos中, .代表当前路径,也就是E:\MyCode\AndroidCode\HelloBabyJNI\src,我们可以简单的使用 . 来指定当前路径

           于是,一个简约的javah指令如下所示:

          

 

  此外,我们还可以在工程menu的bin文件夹下来执行javah指令,只需要将上面的bin替换src则可。当然,最后生成的.h文件在bin文件夹下。

 

 

二、使用MS VC生成dll动态链接库:

     1,创建DLL工程,如同所示:

                 

 

    2,下一步,选择A simple DLL project

                               

 

    3,接下来,生成了我们的HelloJNI工程,切换至File View视图

         首先,导入我们之前生成的HelloBabyJNI.h头文件(可能我的VC环境有问题,我在这儿新建了一个HelloBabyJNI.h文件,拷   贝了我们之前通过javah生成的.h的文件内容)

         第 二,在StdAx.h文件添加如下需要引用的头文件:

                     

  

         第三,在HelloBabyJNI.cpp中添加我们的native method的方法实现,并且加入相应的形参。

  1. <PRE class=cpp name="code">// HelloBabyJNI.cpp : Defines the entry point for the DLL application.  
  2. //  
  3.  
  4. #include "stdafx.h"  
  5.  
  6. BOOL APIENTRY DllMain( HANDLE hModule,  
  7.                        DWORD  ul_reason_for_call,  
  8.                        LPVOID lpReserved) 
  9.     return TRUE; 
  10. //以上为VC自动生成/*  
  11. /* 这就是是java生成的头文件的native方法实现,其命名约定为 Java_包名_方法名  
  12. *  JNIEXPORT JNICALL JNIEnv 以及jobject皆是Jni的关键字 
  13. * 具体实现则完全按照C++语法操作 */ 
  14. JNIEXPORT jint JNICALL Java_com_lover_hellojni_HelloBabyJNI_add 
  15.   (JNIEnv * env, jobject, jint a, jint b) 
  16.      int result =a+b ; 
  17.      return result ; 
  18. </PRE><BR> 
  19. <PRE></PRE> 
  20. <P><SPAN style="FONT-SIZE: 16px">           那么,这个result则是我们本地方法需要返回给java调用者的。</SPAN></P> 
  21. <P><SPAN style="FONT-SIZE: 16px"></SPAN></P> 
  22. <P><SPAN style="FONT-SIZE: 16px">       最后,大功告成前,可别得意。我们需要为我们的工程添加Java JNI的头文件引用,具体添加文件在我们安装的jdk目录下。</SPAN></P> 
  23. <P>具体操作为:在VC的菜单上选择Tools-Options…,打开选项对话框。在Directories文件夹,添加上jdk所在文件夹下的include和include/win32文件夹。</P> 
  24. <P> </P> 
  25. <P></P> 
  26. <P><SPAN style="FONT-SIZE: 16px">   生成成dll动态链接库--->单栏上 Build--->Build HelloBabyJNI.dll ,成功运行后,会在当前工程目录下的</SPAN></P> 
  27. <P><SPAN style="FONT-SIZE: 16px">Debug文件下找到我们创建的HelloBabyJNI.dll动态链接库。</SPAN></P> 
  28. <P><SPAN style="FONT-SIZE: 16px">                   <IMG alt="" src="http://hi.csdn.net/attachment/201108/17/0_1313593245rkRb.gif"></SPAN></P> 
  29. <P><SPAN style="FONT-SIZE: 16px">  </SPAN></P> 
  30. <P><SPAN style="FONT-SIZE: 16px">               </SPAN></P> 
  31. <H2><A name=t3></A>三、运行Java工程</H2> 
  32. <P><SPAN style="FONT-SIZE: 16px">      通过前两个大步骤,我们成功的创建了Java工程以及其所调用的dll动态链接库,为了让系统在调用的时候能够访问到HelloBabyJNI.dll,我只是简单的将其放入C:\Window\System32文件夹下(Window7中)。 成功运行之前创建的Java工程。输出为:</SPAN></P> 
  33. <P><SPAN style="FONT-SIZE: 16px">    </SPAN></P> 
  34. <H2><A name=t4></A>总结:</H2> 
  35. <P><SPAN style="FONT-SIZE: 16px">        在Java原生JNI调用的时候,重点掌握以下几个方面:</SPAN></P> 
  36. <P><SPAN style="FONT-SIZE: 16px">            1、javah指令的掌握 ;</SPAN></P> 
  37. <P><SPAN style="FONT-SIZE: 16px">            2、参数类型的映射 ;</SPAN></P> 
  38. <P><SPAN style="FONT-SIZE: 16px">            3、生成的头文件(.h)中native method方法的理解以及实现上。</SPAN></P> 
  39. <P><SPAN style="FONT-SIZE: 18px">如此,则我们可以很好的掌握Java原生JNI的使用了。</SPAN></P> 
  40. <P>                 </P> 
  41. <P></P> 
  42. <P> </P> 
  43. <PRE></PRE> 
  44. <PRE></PRE> 
  45. <PRE></PRE> 
posted @ 2013-03-12 20:00  天地乐  阅读(280)  评论(0编辑  收藏  举报