java调用c函数_从Java调用c函数

看一下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平台系统属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值