看一下Java本机接口:入门。
2.1概述
[...]编写一个简单的Java应用程序,该应用程序调用C函数来打印“ Hello World!”。该过程包括以下步骤:
创建一个声明本机方法的类(HelloWorld.java)。使用javac编译HelloWorld源文件,从而生成类文件HelloWorld.class。JDK或Java 2 SDK版本提供了javac编译器。使用javah -jni,以产生C头文件(HelloWorld.h)包含函数原型为本地方法实现。JDK或Java 2 SDK版本提供了javah工具。编写本HelloWorld.c机方法的C实现()。将C实现编译到本地库中,创建 Hello-World.dll或libHello-World.so。使用主机环境上可用的C编译器和链接器。使用Java运行时解释器运行HelloWorld程序。类文件(HelloWorld.class)和本机库(HelloWorld.dll或libHelloWorld.so)在运行时加载。本章其余部分将详细说明这些步骤。
2.2声明本机方法
首先以Java编程语言编写以下程序。该程序定义了一个名为HelloWorld的类,其中包含一个本地方法print。
class HelloWorld {
private native void print();
public static void main(String[] args) {
new HelloWorld().print();
}
static {
System.loadLibrary("HelloWorld");
}
}
HelloWorld类定义以print本机方法的声明开始。然后是一个main方法,该方法实例化Hello-World类并为此实例调用print native方法。类定义的最后一部分是静态初始化程序,该初始化程序加载包含print native方法实现的本地库。
在Java编程语言中,诸如print之类的本机方法的声明与常规方法的声明之间有两个区别。本机方法声明必须包含本机修饰符。本机修饰符表示此方法是用另一种语言实现的。而且,本机方法声明以分号(语句终止符)终止,因为类本身没有本机方法的实现。我们将在单独的C文件中实现print方法。
在可以调用本机方法print之前,必须加载实现print的本机库。在这种情况下,我们将本机库加载到HelloWorld该类的静态初始化器中。Java虚拟机在调用HelloWorld类中的任何方法之前会自动运行静态初始化程序,从而确保在调用print native方法之前加载了native库。
我们定义一个主要方法以能够运行HelloWorld该类。 Hello-World.main以与调用常规方法相同的方式调用本地方法print。
System.loadLibrary获取库名称,找到与该名称相对应的本机库,然后将本机库加载到应用程序中。我们将在本书的后面部分讨论确切的加载过程。现在,只需记住,为了 System.loadLibrary("HelloWorld")成功,我们需要创建一个HelloWorld.dll在Win32或libHelloWorld.soSolaris 上调用的本机库。
2.3编译HelloWorld类
定义HelloWorld类之后,将源代码保存在名为HelloWorld.java的文件中。然后使用JDK或Java 2 SDK版本随附的javac编译器来编译源文件:
javac HelloWorld.java
此命令将HelloWorld.class 在当前目录中生成一个文件。
2.4创建本机方法头文件
接下来,我们将使用该javah工具生成一个JNI样式的头文件,该文件在用C实现本机方法时很有用。您可以按如下方式javah在Hello-World该类上运行 :
javah -jni HelloWorld
头文件的名称是类名称,.h其末尾带有“ ”。上面显示的命令生成一个名为的文件HelloWorld.h。我们不会在此处完整列出生成的头文件。头文件中最重要的部分是的函数原型Java_HelloWorld_print,它是实现HelloWorld.print方法的C函数:
JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject);
现在忽略JNIEXPORT和JNICALL宏。您可能已经注意到,即使本机方法的相应声明不接受任何参数,本机方法的C实现也接受两个参数。每个本机方法实现的第一个参数是JNIEnv接口指针。第二个参数是对HelloWorld对象本身的引用(类似于thisC ++中的“ ”指针)。在本书的后面,我们将讨论如何使用JNIEnv接口指针和jobject参数,但是这个简单的示例忽略了这两个参数。
2.5编写本机方法实现
生成的JNI样式头文件可javah帮助您为本机方法编写C或C ++实现。您编写的函数必须遵循在生成的头文件中指定的-prototype。您可以Hello-World.print在C文件中实现该方法,HelloWorld.c如下所示:
#include
#include
#include "HelloWorld.h"
JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv *env, jobject obj) {
printf("Hello World!\n");
return;
}
此本地方法的实现很简单。它使用printf函数显示字符串“ Hello World!”。然后返回。如前所述,参数,JNIEnv指针和对对象的引用都将被忽略。
C程序包括三个头文件:
jni.h-该头文件提供了本机代码调用JNI函数所需的信息。编写本机方法时,必须始终将此文件包含在C或C ++源文件中。 stdio.h-上面的代码段也包含stdio.h该printf 功能,因为它使用了该功能。 HelloWorld.h-使用生成的头文件 javah。它包括该功能的C / C ++原型Java_HelloWorld_print 。2.6编译C源代码并创建本机库
请记住,HelloWorld在HelloWorld.java文件中创建类时 ,您包含了将本地库加载到程序中的一行代码:
System.loadLibrary("HelloWorld");
现在,所有必需的C代码都已编写完毕,您需要编译Hello-World.c并构建此本机库。
不同的操作系统支持不同的方式来构建本机库。在Solaris上,以下命令将构建一个名为libHello-World.so的共享库:
cc -G -I/java/include -I/java/include/solaris HelloWorld.c -o libHelloWorld.so
-G选项指示C编译器生成共享库,而不是常规Solaris可执行文件。由于本书中页面宽度的限制,我们将命令行分为两行。您需要在一行中键入命令,或将命令放在脚本文件中。在上Win32,以下命令HelloWorld.dll 使用Microsoft Visual C ++编译器构建动态链接库(DLL):
cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll
该-MD选项确保将HelloWorld.dll其与Win32多线程C库链接。该-LD选项指示C编译器生成DLL,而不是常规Win32可执行文件。当然,在Solaris和Win32上,都需要输入包含路径,以反映您自己计算机上的设置。
2.7运行程序
至此,您已经准备好两个组件来运行程序。类文件(HelloWorld.class)调用本机方法,而本机库(Hello-World.dll)实现本机方法。
由于HelloWorld该类包含其自己的main方法,因此可以在Solaris或Win32上运行程序,如下所示:
java HelloWorld
您应该看到以下输出:
Hello World!
正确设置本机库路径对于程序运行很重要。本机库路径是Java虚拟机在加载本机库时搜索的目录列表。如果没有正确设置本机库路径,则会看到类似于以下内容的错误:
java.lang.UnsatisfiedLinkError: no HelloWorld in library path
at java.lang.Runtime.loadLibrary(Runtime.java)
at java.lang.System.loadLibrary(System.java)
at HelloWorld.main(HelloWorld.java)
确保本机库位于本机库路径中的目录之一中。如果您在Solaris系统上运行,则LD_LIBRARY_PATH 环境变量用于定义本机库路径。确保它包括包含该libHelloWorld.so文件的目录的名称 。如果libHelloWorld.so文件在当前目录中,则可以在标准外壳程序(sh)或KornShell(ksh)中发出以下两个命令来LD_LIBRARY_PATH 正确设置环境变量:
LD_LIBRARY_PATH=.
export LD_LIBRARY_PATH
C外壳程序(csh或tcsh)中的等效命令如下:
setenv LD_LIBRARY_PATH .
如果您在Windows 95或Windows NT计算机上运行,请确保该文件HelloWorld.dll位于当前目录或PATH环境变量中列出的目录中。
在Java 2 SDK 1.2发行版中,您还可以在java命令行上将本机库路径指定为系统属性,如下所示:
java -Djava.library.path=. HelloWorld
“ -D”命令行选项设置Java平台系统属性。