博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java本地接口(JNI)编程指南和规范(第二章)
阅读量:4028 次
发布时间:2019-05-24

本文共 5409 字,大约阅读时间需要 18 分钟。

原文链接:

第二章 开始

这章通过一个使用"Java Native Interface(JNI)"的一个简单例子来引导你。我们将携一个"Java"应用程序,它调用一个"C"函数来打印"Hello World!"。

 

2.1 概要

"Figure 2.1"(图 2.1)说明这个进程为使用"JDK"或"Java 2 SDK releases"来写的一个简单的Java应用程序,它调用一个"C"函数打印"Hello World!"。这个过程包含以下几步:
1.创建一个类(HelloWorld.java)宣布一个本地方法。
2.用"javac"来编译"HelloWorld"源代码文件,产生"class"文件"HelloWorld.class"."javac"编译器是"JDK"或"Java 2 SDK releases"提供的。
3.使用"javah -jni"来产生一个"C"头文件(HelloWorld.h),它包含函数的原型为本地方法的实现。"javah"工具是"JDK"或"Java 2 SDK releases"提供的。
4.写"C"的本地方法的实现(HelloWorld.c)。
5.编译"C"的实现为一个本地库,创建"HelloWorld.dll"或"libHelloWorld.so"文件。使用在本机环境中可用的"C"编译器和链接器。
6.使用"java runtime interpreter"(java实时解释器)来运行"HelloWorld"程序。"class"文件(HelloWorld.class)和本地库(HelloWorld.dll or libHelloWorld.so)被实时的载入。

 

这章剩余的部分解释这些步骤的细节。

 

                                 1.

                                Create a class
                                that declares the
                                native method
                                 |
                                 |-->HelloWorld.java

               2.                                      3.

               Use javac                            Use javah to
               to compile the                 |---> generate header
               program                        |     file
               |                              |     |
               |--HelloWorld.class -----------|     |-->HelloWorld.h
                     |                                     |
                     |                                     |          4.
                     |                                     |-----> Write the C
                     |                                             implementation
                     |                                     |------ of the native method
                     |                     HelloWorld.c <--|           
                     |                           |
                     |                           |            5.
                     |                           |------->  Compile C
                     |                                      Code and generate
                     |                                 |--  native library
                     |     6.                          | 
                     |--> Run the program              |--> HelloWorld.dll
                          using the java                       |
                          interpreter     <--------------------|
                             |
                             |--> "Hello World!"

Figure 2.1 Steps in Writing and Running the "Hello World" Program

 

2.2 申明本地方法(Declare the Native Method)

你通过用"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"方法实例化"HelloWorld"类,同时调用了"print"本地方法为这个实例。这个类定义的最后部分是一个静态初始化,来载入包含"print"本地方法实现的本地库。

 

在本地方法如"print"的声明和用Java编程语言声明的规则的方法之间有两个不同。本地方法的声明必须包含"native"修饰字符。这个"native"修饰字符指明这个方法用另一种语言来实现。本地方法声明是用分号终止的,声明终止符号,因为在这类自身中本地方法没有实现。我们将在单独的"C"文件中实现"print"方法。

 

在本地方法"print"被调用前,实现"print"的本地库必须被载入。这个例子中,我们在"HelloWorld"类的静态初始化中载入本地库。Java虚拟机自动地运行静态初始化,在"HelloWorld"类中调用任何方法前,因此保证在"print"本地方法被调用前,本地库被载入。

 

我们定义了一个"main"方法能运行"HelloWorld"类。"HelloWorld.main"用和它调用一般规定方法一样方法调用本地方法"print"。

 

"System.loadLibrary"需要一个库名字,定位和这个名字相应的本地库,载入这个本地库到应用程序。我们将在这本书后面讨论详细地载入过程。现在简单地记住为了"System.loadLibrary("HelloWorld")"成功,我们必须创建在"Win32"上名叫"HelloWorld.dll",或在"Solaris"上名叫"libHelloWorld.so"的本地库。

 

2.3 编译"HelloWorld"类

你已经定义了"HelloWorld"类后,保存源代码在"HelloWorld.java"文件中。然后用"JDK"或"Java 2 SDK release"自带的"javac"编译器编译源代码文件:
javac HelloWorld.java

 

这个命令将在当前的目录中产生一个"HelloWorld.class"文件。

 

2.4 创建本地方法的头文件

下一步我们将使用"javah"工具来产生一个"JNI"格式头文件,当用"C"语言来实现本地方法时这头文件是有用的。你能在HelloWorld类上运行"javah",如下:
javah -jni HelloWorld

 

头文件名字是一个带有".h"的类名,".h"扩展它的结尾。上面显示的命令产生了一个名为"HelloWorld.h"的文件。我们这儿将不再完整地列出产生的头文件。头文件最重要的部分是Java_HelloWorld_print的函数原型,它是"C"函数实现了"HelloWorld.print"方法:

JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *, jobject) ;

 

因为现在,忽略"JNIEXPORT"和"JNICALL"宏。我们可能已经注意到,即使虽然对应地本地方法的声明不接受参数,但是本地方法C的实现接受两个参数。对于每个本地方法的实现的第一个参数都是一个"JNIEnv"接口的指针第二个参数是"HelloWorld"对象自身的一个参考(在"C++"中就像"this"指针)。我们将在这本书的后面讨论怎样使用"JNIEnv"接口指针和"jobject"参数,但这个简单的例子忽略这两个参数。

 

2.5 写本地方法的实现

通过"javah"产生的"JNI"风格头文件帮助你为本地方法来写"C"或"C++"的实现。你写的函数必须按照在产生头文件中的详细定义的原型来。你能实现"HelloWorld.print"方法在"HelloWorld.c"的"C"文件中。如下(as follows):
#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"

JNIEXPORT void JNICALL

Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
 printf("Hello World!\n") ;
 return ;
}

 

这个本地方法的实现是简单的。它使用"printf"函数来显示一个字符串"Hello World!",然后放回。对于前面提到的俩那个参数,"JNIEnv"指针和对象(object)的参考被忽略。

 

这个"C"程序包含三个头文件:

.jni.h ---- 这个头文件提供了本地编码需要调用的"JNI"接口的信息。当写本地方法时,你必须总是包含这个头文件在你的"C"或"C++"源代码中。
.stdio.h ----上面的代码片段总是包含"stdio.h",因为它使用了"printf"函数。
.HelloWorld.h ---- 你用"javah"产生的头文件。它为Java_HelloWorld_print函数包含了"C/C++"原型。

 

2.6 编译C源代码和创建一本地库

记住当你在"HelloWorld.java"文件中创建"HelloWorld"类的时候,你包含了一行代码,它载入一个本地库到程序中:
System.loadLibrary("HelloWorld") ;

 

现在所有需要的"C"源代码都写了,你需要编译"HelloWorld.c"和建立本地库。

 

不同的操作系统支持不同的方法来建立本地库。在Solaris,下面的1命令构建一个叫"libHelloWorld.so"的共享库:

cc -G -I/java/include -I/java/include/solaris HelloWorld.c -o libHelloWorld.so

 

"-G"可选命令"C"编译器来产生一个共享库来替代一个规定的"Solaris"的可执行文件。因为本书的篇幅的限制,我们把命令行打断成两行。你需要输入命令在单独一行,或放置这命令在一个脚本文件中。在Win32中,下面命令,来使用"Microsoft Visual C++"编译器,构建一个动态链接库(DLL)(dynamic link library)"HelloWorld.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 运行程序

在这时,你为运行程序准备了两个控件。"class"文件(HelloWorld.class)调用本地方法,和本地库(HelloWorld.dll)实现本地方法。

 

因为"HelloWorld"类包含它自己的"main"方法,你可以在"Solaris"或"Win32"上运行,如下(as follows):

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"文件是在当前目录中。你可以发布如下两个命令在标准的shell(sh)或KornShell(ksh)来建立"LD_LIBRARY_PATH"恰当的环境变量:

LD_LIBRARY_PATH=.
export LD_LIBRARY_PATH

 

在C shell(csh or tcsh)中同样的命令是像下面:

setenv LD_LIBRARY_PATH .

 

如果你运行在"Window 95"或"Windows NT"机器,你确保"HelloWorld.dll"是在当期目录下,或在你PATH环境变量的列表的目录中。

 

在"Java 2 JDK 1.2 release"中,你也能在"java命令行"上详细说明本地库路径作为一个系统属性如下:

java -Djava.library.path=. HelloWorld

 

"-D"命令行选项设置一个Java平台系统属性。设置"java.library.path"属性为"."命令Java virtual machine(Java虚拟机)来在当前目录中搜索本地库。

转载地址:http://rimbi.baihongyu.com/

你可能感兴趣的文章
mint/ubuntu安装搜狗输入法
查看>>
C++动态申请数组和参数传递问题
查看>>
opencv学习——在MFC中读取和显示图像
查看>>
retext出现Could not parse file contents, check if you have the necessary module installed解决方案
查看>>
pyQt不同窗体间的值传递(一)——对话框关闭时返回值给主窗口
查看>>
linux mint下使用外部SMTP(如网易yeah.net)发邮件
查看>>
北京联通华为光猫HG8346R破解改桥接
查看>>
python使用win32*模块模拟人工操作——城通网盘下载器(一)
查看>>
python append 与浅拷贝
查看>>
Matlab与CUDA C的混合编程配置出现的问题及解决方案
查看>>
2017阿里内推笔试题--算法工程师(运筹优化)
查看>>
python自动化工具之pywinauto(零)
查看>>
python自动化工具之pywinauto(四)——批量转换exe视频
查看>>
python一句话之利用文件对话框获取文件路径
查看>>
PaperDownloader——文献命名6起来
查看>>
PaperDownloader 1.5.1——更加人性化的文献下载命名解决方案
查看>>
如何将PaperDownloader下载的文献存放到任意位置
查看>>
C/C++中关于动态生成一维数组和二维数组的学习
查看>>
系统架构:Web应用架构的新趋势---前端和后端分离的一点想法
查看>>
JVM最简生存指南
查看>>