JNI示例

一、JNI简介

JNI:JavaNativeInterface,是Java语言提供的一种通用接口,用于Java代码与本地化代码的交互。所谓本地化代码是指直接编译成的与机器相关的二进制代码,而非Java字节码之类的中间代码。Windows下面的可执行文件,DLL等,Linux下面的可执行文件和SO文件等,都是二进制代码。

JNI允许Java语言编写的程序与其他语言编写的程序库(DLL,SO)或可执行文件进行互操作,包括汇编、C、C++。

JNI产生的原因在于以下几种需求:

(1).你的应用程序需要使用系统相关的功能,而Java代码不支持或是难以办到。这个比较典型的是实现托盘图标,有几种现成的方案都是用的JNI做的,名字好像是叫做TrayIcon和StayOnTop。当然啦,如果是用的Java1.6,那就要另当别论了。

(2).已有其他语言写好的类库或程序,希望Java程序可以使用它们。

(3).出于更高的性能要求,希望使用汇编或是C/C++语言来实现部分功能。

二、JNI的开发步骤

这里以使用C++编写本地化方法实现为例,开发一个使用JNI的Demo程序,具体步骤如下所示:

(1).编写带有native方法的java类

(2).使用javac命令编译所编写的java类

(3).使用javah命令处理类文件,生成C/C++头文件

(4).使用C/C++实现本地方法

(5).将C/C++编写的文件生成动态连接库

三、Demo程序,Demo程序宣示了Java代码中调用C++的输出功能打印字符串,同时演示了使用C++的输入功能读取字符串,并使用System.out.println输出。

1.编写带native方法的Java类

本示例中的源程序就一个Java类。如下所示:

//HelloJNI.java--简单的JNI入门示例。

//2007-4-516:41:45

publicclassHelloJNI{

publicnativevoiddisplayHello();

publicnativevoidshowTime();

privatenativeStringgetLine(Stringprompt);

static{

System.loadLibrary("hello");

}

publicstaticvoidmain(String[]args)throwsException{

HelloJNIhj=newHelloJNI();

System.out.println("==>Demo1:hello");

hj.displayHello();

System.out.println("==>Demo2:time");

hj.showTime();

System.out.println("==>Demo3:input");

Stringinput=hj.getLine("Typealine:");

System.out.println("Usertyped:"+input);

}

}

说明:一共3个native方法,第一个简单的Hello,第二个使用<ctime>头文件中的相关函数计算当前时间,第三个读取输入。注意static语句块:

static{

System.loadLibrary("hello");

}

在JVM载入HelloJNI类的时候加载动态库,System.loadLibrary()中的参数是我们要生成的动态库文件的名字,不包括扩展名,在Windows下面是hello.dll,Linux下面是hello.so,这个由Java自动识别。

2.编译此类

javacHelloJNI生成HelloJNI.class文件

3.使用javahHelloJNI生成C/C++头文件,生成的头文件不用任何修改。如下所示:

/*DONOTEDITTHISFILE-itismachinegenerated*/

#include<jni.h>

/*HeaderforclassHelloJNI*/

#ifndef_Included_HelloJNI

#define_Included_HelloJNI

#ifdef__cplusplus

extern"C"{

#endif

/*

*Class:HelloJNI

*Method:displayHello

*Signature:()V

*/

JNIEXPORTvoidJNICALLJava_HelloJNI_displayHello

(JNIEnv*,jobject);

/*

*Class:HelloJNI

*Method:showTime

*Signature:()V

*/

JNIEXPORTvoidJNICALLJava_HelloJNI_showTime

(JNIEnv*,jobject);

/*

*Class:HelloJNI

*Method:getLine

*Signature:(Ljava/lang/String;)Ljava/lang/String;

*/

JNIEXPORTjstringJNICALLJava_HelloJNI_getLine

(JNIEnv*,jobject,jstring);

#ifdef__cplusplus

}

#endif

#endif

4.编写C/C++实现文件,如下所示:

//HelloJNIImpl.cpp--自己编写的实现文件

//2007-4-516:52:53

#include<jni.h>

#include<iostream>

#include<ctime>

#include<string>

#include<cstdio>

#include<windows.h>

#include"HelloJNI.h"

extern"C"{

//

}

usingnamespacestd;

JNIEXPORTvoidJNICALLJava_HelloJNI_displayHello(JNIEnv*env,jobjectobj){

cout<<"Hello,JNItech.ThisisfromC++!"<<endl;

}

JNIEXPORTvoidJNICALLJava_HelloJNI_showTime(JNIEnv*env,jobjectobj){

time_tsec;

tmt;

time_tloop;

cout<<"时间:";

sec=time(NULL);

t=*localtime(&sec);

unsignedinthour=t.tm_hour;

unsignedintmini=t.tm_min;

unsignedintsecd=t.tm_sec;

if(hour<10){

cout<<"0"<<hour;

}

else{

cout<<hour;

}

cout<<":";

if(mini<10){

cout<<"0"<<mini;

}

else{

cout<<mini;

}

cout<<":";

if(secd<10){

cout<<"0"<<secd;

}

else{

cout<<secd;

}

cout<<endl;

}

JNIEXPORTjstringJNICALLJava_HelloJNI_getLine(JNIEnv*env,jobjectobj,jstringprompt){

charbuf[128]={0};

constchar*str=(env)->GetStringUTFChars(prompt,0);

//printf("%s",str);

cout<<str;

(env)->ReleaseStringUTFChars(prompt,str);

stringbuffer;

getline(cin,buffer);

//scanf("%s",buf);

return(env)->NewStringUTF(buffer.c_str());

}

说明:JNITutorial中使用的居然是像下面这样的代码,env指针的使用应该有误,敬请注意。

JNIEXPORTjstringJNICALL

Java_Prompt_getLine(JNIEnv*env,jobjectobj,jstringprompt)

{

charbuf[128];

constchar*str=(*env)->GetStringUTFChars(env,prompt,0);

printf("%s",str);

(*env)->ReleaseStringUTFChars(env,prompt,str);

...

5.生成本地库文件。笔者使用的vs2008中的C++编译器。vs2008命令行工具生成DLL的命令:

cl-I<头文件目录1>-I<头文件目录2>-LD<C/C++源文件名>-Fe<生成的DLL文件名>

-I选项指定头文件目录,-LD指定C++源文件,-Fe指定生成的DLL文件名。将各个部分替换成实际的情况,实际使用的命令如下:

cl-C:\Java\jdk1.6.0_10\include-IC:\Java\jdk1.6.0_10\include\win32-LDHelloJNIImpl.cpp-Fehello.dll

关于这里的cl命令使用,及在vs2008中使用请看下一篇文章Vs2008与JNI示例。

6.运行结果,如下图所示:

7.自动化。其实步骤都很简单,所以可以使用Ant来完成。下面提供一个ANTBuildfile。使用之前请根据自己的实际情况修改相关属性。

注意:Builfile编码是UTF-8的。

build.xml

<?xmlversion="1.0"encoding="UTF-8"?>

<projectdefault="help"basedir="."name="JNI_Hello">

<propertyname="app.home"value="."></property>

<!--设置头文件的目录,根据JDK具体的安装目录而定-->

<propertyname="h.dir1"value="C:/java/jdk1.5.0_10/include"></property>

<propertyname="h.dir2"value="C:/java/jdk1.5.0_10/include/win32"></property>

<!--设置cl工具的路径,视具体情况而定-->

<propertyname="vc.bin.dir"

value="C:/ProgramFiles/MicrosoftVisualStudio.NET2003/Vc7/bin">

</property>

<propertyname="cpp.name"value="HelloJNIImpl.cpp"></property>

<propertyname="dll.name"value="hello.dll"></property>

<targetname="compile"description="==>编译Java源文件">

<javacsrcdir="${app.home}"destdir="${app.home}">

</javac>

</target>

<targetname="javah"description="==>生成C/C++头文件">

<javahdestdir="${app.home}"force="yes"class="HelloJNI"/>

</target>

<targetname="dll"description="==>调用cl命令生成相关的DLL文件">

<execdir="${app.home}"executable="${vc.bin.dir}/cl.exe"os="WindowsXP">

<!--参数-EHsc好像是VS.NET2003中cl.exe的,可以不加,参考下面的注释行-->

<argline="-EHsc-I${h.dir1}-I${h.dir2}-LD${cpp.name}-Fe${dll.name}"/>

<!--

<argline="-I${h.dir1}-I${h.dir2}-LD${cpp.name}-Fe${dll.name}"/>

-->

</exec>

</target>

<targetname="run"description="==>运行">

<javaclassname="HelloJNI"></java>

</target>

<targetname="all"description="==>自动进行上面任务列表">

<antcalltarget="compile"/>

<antcalltarget="javah"/>

<antcalltarget="dll"/>

<antcalltarget="run"/>

</target>

<targetname="help"description="==>显示帮助信息">

<echo>用法帮助:</echo>

<echo>antcompile编译Java源文件</echo>

<echo>antjavah生成C/C++头文件</echo>

<echo>antdll调用cl命令生成相关的DLL文件</echo>

<echo>antrun运行</echo>

<echo></echo>

<echo>antall自动进行上面任务列表</echo>

<echo>anthelp显示帮助信息</echo>

</target>

</project>

Done!^_^!

JNI还有很多高级的功能,这里我就不说了,一来是不太会,二来也没什么意义。JNI Tutorial上讲得很全面,不错。

相关推荐