JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能.解决JAVA对本地操作的一种方法就是JNI.
JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式).通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法.
简单介绍及应用如下:
第一段:JAVA中所需要做的工作
在JAVA程序中,首先需要在类中声明所调用的库名称,如下:
static
{
System.loadLibrary("goodluck");
}
今天这一节,库的扩展名字可以不用写出来,究竟是DLL还是SO,由系统自己判断.
还需要对将要调用的方法做本地声明,关键字为native.并且只需要声明,而不需要具体实现.如下:
public
native
void
set(int
i);
int
get();
然后编译该JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就会生成C/C++的头文件.
例如程序testdll.java,内容为:
class
testdll
main(String[]
args)
test
=
new
testdll();
test.set(10);
System.out.println(test.get());
用javac
testdll.java编译它,会生成testdll.class.
再用javah
testdll,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件.
第二段:C/C++中所需要做的工作
对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现.然后编译连接成库文件即可.再把库文件拷贝到JAVA程序的路径下面,就可以用JAVA调用C/C++所实现的功能了.
接上例子.我们先看一下testdll.h文件的内容:
/*
DO
NOT
EDIT
THIS
FILE
-
it
is
machine
generated
*/
#include
jni.h
Header
for
#ifndef
_Included_testdll
#define
#ifdef
__cplusplus
extern
"C"
#endif
*
Class:
Method:
get
Signature:
()I
JNIEXPORT
jint
JNICALL
Java_testdll_get
(JNIEnv
*,
jclass);
set
(I)V
Java_testdll_set
jclass,
jint);
在具体实现的时候,我们只关心两个函数原型
和
这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的.而jint是以JNI为中介使JAVA的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用.函数的名称是JAVA_再加上java程序的package路径再加函数名组成的.参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它.
好,下面我们用testdll.cpp文件具体实现这两个函数:
"testdll.h"
i
0;
jclass)
return
i;
j)
j;
编译连接成库文件,本例是在WINDOWS下做的,生成的是DLL文件.并且名称要与JAVA中需要调用的一致,这里就是goodluck.dll
把goodluck.dll拷贝到testdll.class的目录下,java
testdll运行它,就可以观察到结果了.
要在java中调用c语言的库,需要使用Java提供了JNI.
举例说明
在c语言中定义一个 void sayHello()函数(打印Hello World);然后在Java中调用这个函数显示Hello Word.
现在分别从Java和C语言两部分说明:
① Java 部分
首先定义一个HelloNative,在其中申明sayHello函数,函数要申明为Native 类型的.如下:
public class HelloNative {
public native void sayHello();
编译这个类,生成class文件:
javac HelloWorld.java
利用javah生成需要的h文件
javah HelloNative
生成的 h文件大概如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include jni.h
/* Header for class HelloNative */
#ifndef _Included_HelloNative
#define _Included_HelloNative
#ifdef __cplusplus
extern "C" {
* Class: HelloNative
* Method: sayHello
* Signature: ()V
JNIEXPORT void JNICALL Java_HelloNative_sayHello
(JNIEnv *, jobject);
可以看一下上面自动生成的程序,程序include了jni.h,这个头文件在 $JAVA_HOME下的include文件夹下. 还可以发现生成的函数名是在之前的函数名前面加上了Java_HelloNative.
根据上面生成的h文件编写相应的代码实现,建立一个 HelloNative.cpp用来实现显示Hello World的函数.如下:
#include stdio.h
#include "HelloNative.h"
JNIEXPORT void JNICALL Java_HelloNative_sayHello(JNIEnv *, jobject)
printf("Hello World!\n");
代码编写完成之后,我们再用gcc编译成库文件,命令如下;
这样就会在当前目录下生成一个libHelloNative.so的库文件.这时需要的库已经生成,在C语言下的工作已经完成了.
此时此刻呢需要在Java中编写一个程序测试一下.在程序前,需要将我们的库载入进去.载入的方法是调用Java的 System.loadLibrary("HelloNative");
public class TestNative
static {
try {
System.loadLibrary("HelloNative");
catch(UnsatisfiedLinkError e) {
System.out.println( "Cannot load hello library:\n " + e.toString() );
public static void main(String[] args) {
HelloNative test = new HelloNative();
test.sayHello();
但是再编译后,运行的时候,问题又出现了.
Cannot load hello library:
java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path
Exception in thread "main" java.lang.UnsatisfiedLinkError: HelloNative.sayHello()V
at HelloNative.sayHello(Native Method)
载入库失败,但是库明明就是放在当前文件夹下的,怎么会载入失败呢?
用System.getProperty("java.library.path")查看,发现java.library.path中并不u存在当前的目录.主要有以下的几个解决办法:
①.) 将生成的库复制到java.library.path有的路径中去,当然这样不是很好
这样之后程序就能够成功的运行了.可以看见显示的"Hello World!"了
以上就是土嘎嘎小编为大家整理的java代码给c调用相关主题介绍,如果您觉得小编更新的文章只要能对粉丝们有用,就是我们最大的鼓励和动力,不要忘记讲本站分享给您身边的朋友哦!!