什么是JNI?Java Native Interface(Java本地接口)的简写。使用这个接口,可以轻松实现java对动态链接库(Dynamic Link Library(.dll/.so)文件的调用,以实现工程存在的一些C/C++的功能。本文主要结合vc++6.0与java编程。
一、建立java文件,文件名称为javacall.java
注意点:1、要对dll里面的方法做本地声明
2、加载dll
示例代码:
public class javacall
{
static
{
System.loadLibrary("jnidll"); // 注意:不写扩展名,名字要与dll的文件名一致.
}
public native static int add(int i, int j);
public static void main(String[] args)
{
javacall jc = new javacall();
int nRet = jc.add(2, 3);
System.out.println(nRet);
}
}
二、控制台编译
javac javacall.java ------如果没有错,进行下一步
javah javacall ------生成javacall.h这个头文件
javacall.h文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class javacall */
#ifndef _Included_javacall
#define _Included_javacall
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: javacall
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_javacall_add
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
三、实现步骤一中声明的方法
打开VC++6.0,建立空工程,工程名称为jnidll。把javacall.h放到该工程中导入。新建一个javacall.cpp源文件:
#include "javacall.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *)
{
JNIEnv *env;
vm->GetEnv((void**)&env, JNI_VERSION_1_2);
/*jclass cls = env->FindClass("jnicli/DatabaseJNI");
if (cls == NULL) {
printf("Class jnicli/DatabaseJNI is not found/n");
} else {
env->RegisterNatives(cls, fastdbApiMethods, itemsof(fastdbApiMethods));
}*/
return JNI_VERSION_1_2;
}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *)
{
JNIEnv *env;
vm->GetEnv((void**)&env, JNI_VERSION_1_2);
/*jclass cls = env->FindClass("jnicli/DatabaseJNI");
env->UnregisterNatives(cls);*/
}
JNIEXPORT jint JNICALL Java_javacall_add(JNIEnv *env, jclass cls, jint a, jint b)
{
return (a + b);
}
四、编译和调试
生成动态库jnidll.dll后,把该文件放入工作目录(F:/workspace/mytest)中,主要包含下列文件:
a、javacall.java;
b、javacall.class;
c、jnidll.dll
结果显示:
5
说明
1)在JAVA程序中,首先需要在类中声明所调用的库名称System.loadLibrary(String libname),在库的搜寻路径中定位这个库。定位库的具体操作依赖于操作系统。在windows下,首先从当前目录查找,然后再搜寻PATH环境变量列出的目录.如果找不到该库,则会抛出UnsatisfiedLinkError.
2)这里加载的是JNI生成的dll,而不是其他生成的dll的名称.在这里库的扩展名字可以不用写出来,究竟是.dll还是.so由系统自己判断.
3)还需要对将要调用的方法做本地声明,关键字为native.并且只需要声明,而不需要具体实现.
4)如果加了static表明是静态方法,如果不加表明是一般的方法.加与不加生成的头文件中有一个参数不同.
解释:
1)加了static和不加只是一个参数的区别吗,就是jclass的不同,不加static这里就是jobject.
2)这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的.而jstring是以JNI为中介使JAVA的String类型与本地的string沟通的一种类型,我们可以视而不见,就当做String使用(具体对应见表一).函数的名称是JAVA_再加上java程序的package路径再加函数名组成的(参见有包的情况).参数中我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们可以通过深入研究隐式调用它.
在C和Java编程语言之间传送值时,需要理解这些值类型在这两种语言间的对应关系。这些都在头文件jni.h中,用typedef语句声明了这些类在目标平台上的代价类。头文件也定义了常量如:JNI_FALSE=0和JNI_TRUE=1;表一说明了Java类型和C类型之间的对应关系。
表一 Java类型和C类型
Java编程语言 | C编程语言 | 字节 |
boolean | jboolean | 1 |
byte | jbyte | 1 |
char | jchar | 2 |
short | jshort | 2 |
int | jint | 4 |
long | jlong | 8 |
float | jfloat | 4 |
double | jdouble | 8 |