Java JNI Programming基础知识介绍

Java JNI Programming基础知识介绍

一、JNI 的特点:

JNI有一个很重要的优点,就是在你充分利用Java的跨平台特性的前提下,你仍然可以利用其它编程语言。JNI是JVM实现很重要的一部分,是允许Java应用调用本地代码(native code)或本地代码调用Java应用的一个双向接口。下图就显示了这两者之间的关系:
Java JNI Programming基础知识介绍
JNI支持两种类型的native code: 本地库和本地应用程序
1. 你可以使用JNI写出本地方法,允许Java程序调用由本地方法实现的函数,这在jvm的实现里有大量的应用。我们从jdk的源码里也可以看到大量的这种示例。
2. JNI还支持调用接口(invocation interface),它允许你在本地应用程序(通常是C/C++代码编写)里嵌入jvm的实现,本地应用可以链接实现了jvm的本地库,接着使用调用接口来调用Java中的一些类的方法。比如,使用C编写的Web浏览器,可以执行一个applet代码片段。
总之一句话,JNI建立了Java语言和native code之间的一种双向调用关系。


下面我们看看,一个简单的jni程序如何编写?

二、简单示例:

 

示例1: HelloWorld.java, 即调用一个C函数,打印一个简单的字符串
Java JNI Programming基础知识介绍packagejnitest;Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍
publicclassHelloWorld{
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍
publicHelloWorld(){
Java JNI Programming基础知识介绍}

Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍static{
Java JNI Programming基础知识介绍System.loadLibrary(
"helloworld");
Java JNI Programming基础知识介绍}

Java JNI Programming基础知识介绍publicnativevoiddisplayHelloWorld();
Java JNI Programming基础知识介绍
publicnativevoiddisplayString(Stringsz);
Java JNI Programming基础知识介绍
publicnativeStringechoString(Stringsz);
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍
publicstaticvoidmain(String[]args){
Java JNI Programming基础知识介绍HelloWorldhelloworld
=newHelloWorld();
Java JNI Programming基础知识介绍Stringt
=helloworld.echoString("测试一下中文");
Java JNI Programming基础知识介绍System.out.println(t);
Java JNI Programming基础知识介绍}

Java JNI Programming基础知识介绍}
Sysem.loadLibrary在static段里,表示在类HelloWorld初始化时,动态加载一个动态库,win32里这个库名应该叫helloworld.dll。这样任何一个HelloWorld实例都可以动态调用helloworld.dll中的方法了。
第一步,我们先build出class文件。
第二步,针对上边的jnitest.class文件,使用javah为其生成C代码中的头文件
cd E:/java/jbproject/jnitest/classes
javah jnitest.HelloWorld
这时我们可以看到生成的头文件名叫jnitest_HelloWorld.h,它的内容如下:

Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍/*DONOTEDITTHISFILE-itismachinegenerated*/
Java JNI Programming基础知识介绍#include<jni.h>
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍/*Headerforclassjnitest_HelloWorld*/
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍#ifndef_Included_jnitest_HelloWorld
Java JNI Programming基础知识介绍
#define_Included_jnitest_HelloWorld
Java JNI Programming基础知识介绍#ifdef__cplusplus
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍
extern"C"{
Java JNI Programming基础知识介绍
#endif
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍/*
Java JNI Programming基础知识介绍*Class:jnitest_HelloWorld
Java JNI Programming基础知识介绍*Method:echoString
Java JNI Programming基础知识介绍*Signature:(Ljava/lang/String;)Ljava/lang/String;
Java JNI Programming基础知识介绍
*/

Java JNI Programming基础知识介绍JNIEXPORTjstringJNICALLJava_jnitest_HelloWorld_echoString
Java JNI Programming基础知识介绍(JNIEnv
*,jobject,jstring);
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍#ifdef__cplusplus
Java JNI Programming基础知识介绍}

Java JNI Programming基础知识介绍#endif
Java JNI Programming基础知识介绍#endif
Java JNI Programming基础知识介绍
需要说明的是,#ifdef__cplusplus
Java JNI Programming基础知识介绍
extern"C"{
#endif
}
表示该头文件也可以用于C++代码的make和link。
下面,我们可以写出本地方法
Java_jnitest_HelloWorld_echoString的实现了。
第二步:实现本地方法.
在刚才的目录
E:/java/jbproject/jnitest/classes下边,我们新建一个文件helloworldimp.cpp。内容如下:
Java JNI Programming基础知识介绍#include<jni.h>
Java JNI Programming基础知识介绍#include"jnitest_HelloWorld.h"
Java JNI Programming基础知识介绍#include<stdio.h>
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍JNIEXPORTjstringJNICALLJava_jnitest_HelloWorld_echoString
Java JNI Programming基础知识介绍(JNIEnv
*env,jobjectobj,jstringsz)
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍
{
Java JNI Programming基础知识介绍
returnsz;
Java JNI Programming基础知识介绍}
这里采用最简单的实现,直接将参数sz的值返回,不作任何改变。

第三步:是build出动态库helloworld.dll,希望你的机器里已经安装好了VC6或者VC7/8(VS2002,2003或者2005)。这里以VC6.0为例,并且采用命令行方式来build。进入到VC的安装目录,这里是D:/msdev/VC98/Bin
编译命令cl就在此目录下边,这个目录下边有个环境变量的批处理文件VCVARS32.bat,我们拿来改一下就可以用了。
在这里,我为它专门加入了jni要使用的头文件,为了编译java代码,把java的ClassPath也加进来了。其内容如下:

Java JNI Programming基础知识介绍@echooff
Java JNI Programming基础知识介绍rem
Java JNI Programming基础知识介绍rem
RootofVisualDeveloperStudioCommonfiles.
Java JNI Programming基础知识介绍setVSCommonDir=D:msdev
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍
rem
Java JNI Programming基础知识介绍rem
RootofVisualDeveloperStudioinstalledfiles.
Java JNI Programming基础知识介绍rem
Java JNI Programming基础知识介绍
setMSDevDir=D:msdevCommonmsdev98
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍
rem
Java JNI Programming基础知识介绍rem
RootofVisualC++installedfiles.
Java JNI Programming基础知识介绍rem
Java JNI Programming基础知识介绍
setMSVCDir=D:msdevVC98
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍
rem
Java JNI Programming基础知识介绍rem
VcOsDirisusedtohelpcreateeitheraWindows95orWindowsNTspecificpath.
Java JNI Programming基础知识介绍rem
Java JNI Programming基础知识介绍
setVcOsDir=WIN95
Java JNI Programming基础知识介绍
if"%OS%"=="Windows_NT"setVcOsDir=WINNT
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍
rem
Java JNI Programming基础知识介绍
echoSettingenvironmentforusingMicrosoftVisualC++tools.
Java JNI Programming基础知识介绍rem
Java JNI Programming基础知识介绍

Java JNI Programming基础知识介绍if"%OS%"=="Windows_NT"setPATH=%MSDevDir%BIN;%MSVCDir%BIN;%VSCommonDir%TOOLS%VcOsDir%;%VSCommonDir%TOOLS;%MSVCDir%DEBUG;%VSCommonDir%OSSYSTEM;%PATH%
Java JNI Programming基础知识介绍
if"%OS%"==""setPATH="%MSDevDir%BIN";"%MSVCDir%BIN";"%VSCommonDir%TOOLS%VcOsDir%";"%VSCommonDir%TOOLS";"%windir%SYSTEM";"%PATH%";%VSCommonDir%OSSYSTEM
Java JNI Programming基础知识介绍
setINCLUDE=%MSVCDir%ATLINCLUDE;%MSVCDir%INCLUDE;%MSVCDir%MFCINCLUDE;%INCLUDE%
Java JNI Programming基础知识介绍
setLIB=%MSVCDir%LIB;%MSVCDir%MFCLIB;%LIB%
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍
remsetVcOsDir=
Java JNI Programming基础知识介绍remsetVSCommonDir=
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍remmodifiedbyxionghe,antpath,classpathetc.
Java JNI Programming基础知识介绍setpath=%path%;d:/jakarta-ant/bin
Java JNI Programming基础知识介绍
setJAGUAR_JDK13=d:/sharedjdk1.3.1_11
Java JNI Programming基础知识介绍
setJAGUAR_JDK14=d:/sharedjdk1.4.2_06
Java JNI Programming基础知识介绍
setJAGUAR_JDK15=d:/sharedjdk1.5.0_01
Java JNI Programming基础知识介绍
setJAVA_HOME=%JAGUAR_JDK14%
Java JNI Programming基础知识介绍
setPATH=%JAVA_HOME%bin;%JAVA_HOME%/jre/bin;%PATH%
Java JNI Programming基础知识介绍
setOLD_CLASSPATH=%CLASSPATH%
Java JNI Programming基础知识介绍
setCLASSPATH=.;%JAVA_HOME%/lib/dt.jar;%JAVA_HOME%/lib/tools.jar;%JAVA_HOME%/jre/lib/rt.jar
Java JNI Programming基础知识介绍
setCLASSPATH=%CLASSPATH%;%OLD_CLASSPATH%
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍
setINCLUDE=%JAVA_HOME%/include;%JAVA_HOME%/include/win32;%INCLUDE%
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍
startcmd
我们在Run窗口里直接运行D:/msdev/VC98/Bin/vcvars32,就会新启一个带有C++以及Java JNI相关环境变量的cmd窗口。进入到刚才的class目录,运行:
cl -MD -LD helloworldimp.cpp -Fehelloworld.dll
动态库即可build成功。
于是我们可以运行java jnitest.HelloWorld,得到结果了。
稍复杂一点的例子,改变本地函数中的参数值。


三、复杂一点的例子:

 

的fs
我们看看下边的这个类:

Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍publicclassPrompt{
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍
publicPrompt(){
Java JNI Programming基础知识介绍}

Java JNI Programming基础知识介绍privatenativeStringgetLine(Stringprompt);
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍
static{
Java JNI Programming基础知识介绍System.loadLibrary(
"helloworld");
Java JNI Programming基础知识介绍}

Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍publicstaticvoidmain(String[]args){
Java JNI Programming基础知识介绍Promptprompt
=newPrompt();
Java JNI Programming基础知识介绍Stringinput
=prompt.getLine("Typealine:");
Java JNI Programming基础知识介绍System.out.println(
"usertyped:"+input);
Java JNI Programming基础知识介绍}

Java JNI Programming基础知识介绍}
Prompt类,就是想调用C代码中的用户输入,然后把输入的东西回显出来,就这么简单,但是返回值是用户输入的串,不是参数里的prompt值。加载的动态库依然借用前边的helloworld.dll,这里不带包名,以与前例区分。
使用javah生成的头文件Prompt.h如下:

Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍/*DONOTEDITTHISFILE-itismachinegenerated*/
Java JNI Programming基础知识介绍#include<jni.h>
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍/*HeaderforclassPrompt*/
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍#ifndef_Included_Prompt
Java JNI Programming基础知识介绍
#define_Included_Prompt
Java JNI Programming基础知识介绍#ifdef__cplusplus
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍
extern"C"{
Java JNI Programming基础知识介绍
#endif
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍/*
Java JNI Programming基础知识介绍*Class:Prompt
Java JNI Programming基础知识介绍*Method:getLine
Java JNI Programming基础知识介绍*Signature:(Ljava/lang/String;)Ljava/lang/String;
Java JNI Programming基础知识介绍
*/

Java JNI Programming基础知识介绍JNIEXPORTjstringJNICALLJava_Prompt_getLine
Java JNI Programming基础知识介绍(JNIEnv
*,jobject,jstring);
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍#ifdef__cplusplus
Java JNI Programming基础知识介绍}

Java JNI Programming基础知识介绍#endif
Java JNI Programming基础知识介绍#endif
Java JNI Programming基础知识介绍
下边是完整的实现,将前例和本例的合到了一起(helloworldimp.cpp)。
Java JNI Programming基础知识介绍#include<jni.h>
Java JNI Programming基础知识介绍#include"jnitest_HelloWorld.h"
Java JNI Programming基础知识介绍#include"Prompt.h"
Java JNI Programming基础知识介绍#include<stdio.h>
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍JNIEXPORTjstringJNICALLJava_jnitest_HelloWorld_echoString
Java JNI Programming基础知识介绍(JNIEnv
*env,jobjectobj,jstringsz)
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍
{
Java JNI Programming基础知识介绍
returnsz;
Java JNI Programming基础知识介绍}

Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍
/**
Java JNI Programming基础知识介绍*PromptDllfunctionentry
Java JNI Programming基础知识介绍
*/

Java JNI Programming基础知识介绍JNIEXPORTjstringJNICALLJava_Prompt_getLine
Java JNI Programming基础知识介绍(JNIEnv
*env,jobjectobj,jstringprompt)
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍
{
Java JNI Programming基础知识介绍
charbuf[128];
Java JNI Programming基础知识介绍
constchar*str;//charisjustthejbyte
Java JNI Programming基础知识介绍str=(env)->GetStringUTFChars(prompt,NULL);
Java JNI Programming基础知识介绍Java JNI Programming基础知识介绍