一、JNI 的特点:
JNI有一个很重要的优点,就是在你充分利用Java的跨平台特性的前提下,你仍然可以利用其它编程语言。JNI是JVM实现很重要的一部分,是允许Java应用调用本地代码(native code)或本地代码调用Java应用的一个双向接口。下图就显示了这两者之间的关系:
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函数,打印一个简单的字符串
packagejnitest;
publicclassHelloWorld...{
publicHelloWorld()...{
}
static...{
System.loadLibrary("helloworld");
}
publicnativevoiddisplayHelloWorld();
publicnativevoiddisplayString(Stringsz);
publicnativeStringechoString(Stringsz);
publicstaticvoidmain(String[]args)...{
HelloWorldhelloworld=newHelloWorld();
Stringt=helloworld.echoString("测试一下中文");
System.out.println(t);
}
}
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,它的内容如下:
/**//*DONOTEDITTHISFILE-itismachinegenerated*/
#include<jni.h>
/**//*Headerforclassjnitest_HelloWorld*/
#ifndef_Included_jnitest_HelloWorld
#define_Included_jnitest_HelloWorld
#ifdef__cplusplus
extern"C"...{
#endif
/**//*
*Class:jnitest_HelloWorld
*Method:echoString
*Signature:(Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORTjstringJNICALLJava_jnitest_HelloWorld_echoString
(JNIEnv*,jobject,jstring);
#ifdef__cplusplus
}
#endif
#endif
需要说明的是,#ifdef__cplusplus
extern"C"...{
#endif
}
表示该头文件也可以用于C++代码的make和link。
下面,我们可以写出本地方法Java_jnitest_HelloWorld_echoString的实现了。
第二步:实现本地方法.
在刚才的目录E:\java\jbproject\jnitest\classes下边,我们新建一个文件helloworldimp.cpp。内容如下:
#include<jni.h>
#include"jnitest_HelloWorld.h"
#include<stdio.h>
JNIEXPORTjstringJNICALLJava_jnitest_HelloWorld_echoString
(JNIEnv*env,jobjectobj,jstringsz)
...{
returnsz;
}
这里采用最简单的实现,直接将参数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也加进来了。其内容如下:
@echooff
rem
remRootofVisualDeveloperStudioCommonfiles.
setVSCommonDir=D:msdev
rem
remRootofVisualDeveloperStudioinstalledfiles.
rem
setMSDevDir=D:msdevCommonmsdev98
rem
remRootofVisualC++installedfiles.
rem
setMSVCDir=D:msdevVC98
rem
remVcOsDirisusedtohelpcreateeitheraWindows95orWindowsNTspecificpath.
rem
setVcOsDir=WIN95
if"%OS%"=="Windows_NT"setVcOsDir=WINNT
rem
echoSettingenvironmentforusingMicrosoftVisualC++tools.
rem
if"%OS%"=="Windows_NT"setPATH=%MSDevDir%BIN;%MSVCDir%BIN;%VSCommonDir%TOOLS%VcOsDir%;%VSCommonDir%TOOLS;%MSVCDir%DEBUG;%VSCommonDir%OSSYSTEM;%PATH%
if"%OS%"==""setPATH="%MSDevDir%BIN";"%MSVCDir%BIN";"%VSCommonDir%TOOLS%VcOsDir%";"%VSCommonDir%TOOLS";"%windir%SYSTEM";"%PATH%";%VSCommonDir%OSSYSTEM
setINCLUDE=%MSVCDir%ATLINCLUDE;%MSVCDir%INCLUDE;%MSVCDir%MFCINCLUDE;%INCLUDE%
setLIB=%MSVCDir%LIB;%MSVCDir%MFCLIB;%LIB%
remsetVcOsDir=
remsetVSCommonDir=
remmodifiedbyxionghe,antpath,classpathetc.
setpath=%path%;d:\jakarta-ant\bin
setJAGUAR_JDK13=d:\sharedjdk1.3.1_11
setJAGUAR_JDK14=d:\sharedjdk1.4.2_06
setJAGUAR_JDK15=d:\sharedjdk1.5.0_01
setJAVA_HOME=%JAGUAR_JDK14%
setPATH=%JAVA_HOME%bin;%JAVA_HOME%\jre\bin;%PATH%
setOLD_CLASSPATH=%CLASSPATH%
setCLASSPATH=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\jre\lib\rt.jar
setCLASSPATH=%CLASSPATH%;%OLD_CLASSPATH%
setINCLUDE=%JAVA_HOME%\include;%JAVA_HOME%\include\win32;%INCLUDE%
startcmd
我们在Run窗口里直接运行D:\msdev\VC98\Bin\vcvars32,就会新启一个带有C++以及Java JNI相关环境变量的cmd窗口。进入到刚才的class目录,运行:
cl -MD -LD helloworldimp.cpp -Fehelloworld.dll
动态库即可build成功。
于是我们可以运行java jnitest.HelloWorld,得到结果了。
稍复杂一点的例子,改变本地函数中的参数值。
三、复杂一点的例子:
的fs
我们看看下边的这个类:
publicclassPrompt...{
publicPrompt()...{
}
privatenativeStringgetLine(Stringprompt);
static...{
System.loadLibrary("helloworld");
}
publicstaticvoidmain(String[]args)...{
Promptprompt=newPrompt();
Stringinput=prompt.getLine("Typealine:");
System.out.println("usertyped:"+input);
}
}
Prompt类,就是想调用C代码中的用户输入,然后把输入的东西回显出来,就这么简单,但是返回值是用户输入的串,不是参数里的prompt值。加载的动态库依然借用前边的helloworld.dll,这里不带包名,以与前例区分。
使用javah生成的头文件Prompt.h如下:
/**//*DONOTEDITTHISFILE-itismachinegenerated*/
#include<jni.h>
/**//*HeaderforclassPrompt*/
#ifndef_Included_Prompt
#define_Included_Prompt
#ifdef__cplusplus
extern"C"...{
#endif
/**//*
*Class:Prompt
*Method:getLine
*Signature:(Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORTjstringJNICALLJava_Prompt_getLine
(JNIEnv*,jobject,jstring);
#ifdef__cplusplus
}
#endif
#endif
下边是完整的实现,将前例和本例的合到了一起(helloworldimp.cpp)。
#include<jni.h>
#include"jnitest_HelloWorld.h"
#include"Prompt.h"
#include<stdio.h>
JNIEXPORTjstringJNICALLJava_jnitest_HelloWorld_echoString
(JNIEnv*env,jobjectobj,jstringsz)
...{
returnsz;
}
/**//**
*PromptDllfunctionentry
*/
JNIEXPORTjstringJNICALLJava_Prompt_getLine
(JNIEnv*env,jobjectobj,jstringprompt)
...{
charbuf[128];
constchar*str;//charisjustthejbyte
str=(env)->GetStringUTFChars(prompt,NULL);
if(str==NULL)...{
returnNULL;/**//*OutOfMemoryErroralreadythrown*/
}
printf("%s",str);
(env)->ReleaseStringUTFChars(prompt,str);
/**//*Weassumeherethattheuserdoesnottypemorethan
*127characters*/
scanf("%s",buf);
return(env)->NewStringUTF(buf);
}
运行java -Djava.library.path=D:\msdev\MyProjects\helloworld Prompt,结果如下:
Type a line: fjkal
user typed: fjkal
注意,这里需要指定jvm的java.library.path值,表示load动态库时的搜索路径,或者你把生成的动态库拷贝到PATH路径中的任一目录里也可以,但不推荐这么做。
还要注意一点的是C++代码和C代码里env的调用形式不太一样。
C++: (env)->ReleaseStringUTFChars(prompt,str);
而C:(env*)->ReleaseStringUTFChars(env, prompt,str);
前边的实现里,必须作出jstring类型到char*的转换,并且适时的要释放内存,否则会出现内存泄漏。
这是一些比较简单的例子。后边会有适当的篇幅介绍jni以及jvm中一些比较复杂的应用。
分享到:
相关推荐
我们将涵盖JNI的基础知识以及一些更高级的编程挑战。 **目标读者**: - 对于想要学习如何在Java应用中调用本地C/C++代码或者如何在本地C/C++应用中调用Java代码的开发者来说,本教程是一个很好的资源。 - 所有的...
1. **初始化Java环境**:使用JNI函数初始化Java环境。 2. **加载Java类**:查找并加载所需的Java类。 3. **调用Java方法**:通过JNI函数调用Java方法。 4. **释放资源**:确保正确地释放所有资源,包括Java环境。 #...
它通过提供一套API(Application Programming Interface),使Java应用能够与本地代码进行交互。这一机制对于以下几种情况非常有用: 1. **性能优化**:某些计算密集型的任务,如图像处理、视频编码等,使用C/C++...
根据提供的文件信息,我们可以从《Server Based ...综上所述,《Server Based Java Programming》这本书覆盖了从基础概念到高级实践的广泛内容,对于希望深入学习服务器端Java编程的开发者来说是一本宝贵的参考资料。
Java程序设计与JNI手册详细介绍了Java Native Interface(JNI)的基础和常用技术,旨在帮助开发者快速有效地开发自己的JNI解决方案。JNI是Java软件开发工具包(SDK)的一部分,它允许Java代码调用用其他语言(如C和...
### Java JNI 技术文档教程知识点详解 #### 一、JNI技术概述 **Java Native Interface (JNI)** 是Java平台的一项强大特性,它允许Java应用程序调用用其他编程语言(如C或C++)编写的本地代码,同时也支持从这些...
- GDAPI(General Desktop Application Programming Interface)是一个Java库,提供了对Windows注册表的高级操作接口。 - 它基于JNI(Java Native Interface),允许Java应用程序直接调用Windows注册表API。 2. *...
JNI(Java Native Interface)是 Java programming language 的一部分,允许 Java 代码与 native 代码进行交互。下面是关于在 VS2008 中调试 JNI 的心得,主要通过截图一步一步展示如何写 JNI 代码。 JNI 基础知识 ...
JNI(Java Native Interface)是一种允许Java代码调用本地应用程序接口(Native Application Programming Interfaces,如 C 或 C++ 代码)的方法。在某些场景下,我们需要通过 JNI 调用来获取 Java 窗口的句柄,这在...
7. **JNI(Java Native Interface)**:Java与本地代码交互的接口,允许Java程序调用C/C++库。 8. **JIT(Just-In-Time)编译器**:JVM的一种优化技术,将热点代码编译为本地机器码以提高运行效率。 9. **类文件...
1. **数据类型映射**:JNI定义了一套类型映射规则,用于转换Java类型和C/C++类型。 2. **异常处理**:JNI提供了专门的异常处理机制,用于处理在调用本地方法过程中可能发生的错误。 3. **资源管理**:在使用JNI时,...
1. **Java编程基础**:在理解Java与Photoshop的交互之前,首先需要具备扎实的Java编程基础,包括语法、面向对象编程、异常处理、集合框架、IO流等。这些是编写任何Java程序的基础,也是与其他软件进行交互的前提。 ...
An example-filled guide to the Java programming language and core APIs. Java Technology Home Page Training for the Java programming language Directory of various training resources. Demonstration ...
Best practices for using the Java Native Interface Techniques and tools for averting the 10 most common JNI programming mistakes.
本书《Java NIO Programming Cookbook》旨在深入浅出地介绍如何利用Java NIO进行高效的I/O编程,并提供了源码供读者实践和学习。 在Java NIO中,`ByteBuffer`是核心类之一,它用于存储和读写数据。`...
`C++ GUI Programming with Qt 4.chm`可能就是一本关于如何使用C++和Qt创建GUI的参考资料,虽然没有直接提供关于JNI的细节,但它可以帮助理解C++和GUI编程的基本原理,这对于在Java中通过JNI调用Qt库是非常有帮助的...
4. **JNI(Java Native Interface)**:学习如何通过JNI与C/C++原生代码交互,以利用Java无法直接提供的系统功能或优化性能。 5. **内存管理和垃圾回收**:理解Java内存模型,包括堆内存、栈内存和方法区,以及垃圾...
1. **Java语言基础**:在Java游戏编程中,首先需要理解的是Java的基础语法,包括类、对象、继承、多态等面向对象编程概念。Java的垃圾回收机制使得内存管理变得相对简单,这对于游戏开发中的资源管理和性能优化至关...
Unlike error-prone JNI programming that is hard to use and deploy, J/Invoke lets you access native libraries by simply declaring native methods, and calling them from pure Java. Java programmers can ...