现在的位置: 首页 > 综合 > 正文

JNI使用方法

2018年06月07日 ⁄ 综合 ⁄ 共 2449字 ⁄ 字号 评论关闭

Java通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在Windows平台下是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使Java可以实现和本地机器的紧密联系,调用系统级的各接口方法

使用的简单流程:

一、Java中所需要做的工作

1、在Java程序中,首先需要在类中声明所调用的库名称,如

static {
System.loadLibrary(“testdll”);
}

这里库的扩展名可以不用写出来,究竟是DLL还是SO,由系统自己判断

2、还需要对将要调用的方法做本地声明,关键字为native。且只需要声明,而不需要具体实现

public native static void set(int i);
public native static int get();

得到的Java程序如下:TestJNI.java

public class TestJNI {
	static {
		System.loadLibrary("testdll");
	}
	public native static int get();
	public native static void set(int i);
	public static void main(String[] args) {
		testdll test = new testdll();
		test.set(10);
		System.out.println(test.get());
	}
}

3、使用javac TestJNI.java编译它,得到TestJNI.class

再用javah TestJNI,则会在当前目录下生成TestJNI.h文件

 注意:用javah命令生成相应h头文件的时候有可能会出现无法找到相应class文件的错误,建议使用如下格式在控制台生成.h头文件
D:\>javah -classpath . testdll

二、C/C++中所需要做的工作

1、打开VC++,新建工程->win32 DLL,在向导中选择空工程。然后编写testdll.cpp文件

#include <windows.h>
#include "TestJNI.h"
int i = 0;
JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)
{
return i;
}
JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j)
{
i = j;
}
int WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) 
{ 
return TRUE ; 
}

说明:

(1)必须有DllMain函数,并且DllMain必须返回TRUE,否则系统将终止程序并弹出一个“启动程序时出错”对话框,其他两个为Java中调用的两个函数的实现,解释见最后的补充

(2)把Java编译生成的TestJNI.h加入到C/C++的工程中,否则上面代码的include "TestJNI.h"无法引用到

2、编译上面的testdll.cpp文件,可以生成testdll.dll文件,但是这过程通常会出现:在TestJNI.h中找不到jni.h

解决方法:把Javajdk中的下面这些.h文件复制一份到Microsoft Visual Studio的安装目录下的\VC\include文件夹下,例如笔者的是D:\Program Files\Microsoft Visual Studio 10.0\VC\include

\jdk\include\jni.h
\jdk\include\win32\jawt_md.h
\jdk\include\win32\jni_md.h

三、结合起来

1、生成的DLL文件的名称要跟Java代码中需要调用的testdll一样,如果不同可以修改文件名,这里是testdll.dll

2、然后把该dll文件拷贝到TestJNI.class文件的目录下。

3、使用java testdll 运行它,就可以观察到结果

说明:如果运行java testdll 出现错误:“ 找不到或无法加载主类”,可能是环境变量的classpath键值的分号;掉了,一般掉了这个就会出现这种问题

四、最后对TestJNI.h的内容理解补充

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class TestJNI*/
#ifndef _Included_TestJNI
#define _Included_TestJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: TestJNI
* Method: get
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_TestJNI_get (JNIEnv *, jclass);
/*
* Class: TestJNI
* Method: set
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_TestJNI_set (JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif

在具体实现的时候,我们只关心两个函数原型
JNIEXPORT jint JNICALL Java_TestJNI_get (JNIEnv *, jclass); 和
JNIEXPORT void JNICALL Java_TestJNI_set (JNIEnv *, jclass, jint);
这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使JAVA的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。 

抱歉!评论已关闭.