由于最近项目中需要读取读卡器上的信息,从来没有接触过使用java调用底层动态链接库Dll的这些东西,就到网上搜了一大堆的资料,然后慢慢摸索,学习了JNI和Jnative两种通过Java方式调用Dll文件的方法。
JNI的步骤如下:
1.在java类中先定义了一个方法,不用实现。
public native static int add(int a,int b);//函数声明
如果对native用法不清楚的,可以去google看看,相信就很清楚了。
2.在java类中载入dll文件,dll文件不用扩展名,会自动识别。还有一种方法是用System.load(xxx);里面是需要绝对路径的,扩展名也不能省。
static
{
System.loadLibrary("TestDll");//载入dll
}
3. java类写好后用javac xxx.java进行编译
4. 使用javah -jni xxx.生成头文件。
第3.4点需要注意的是:一般我们都是在做项目,java类前面的包名肯定少不了,所以我们在命令行中编译时需要cd 到指定的java类路径下,例如我在Myeclipse中建立的一个工程,路径如下:D:\workspace\DiskNumber\src\com\tjn\test 先要cd
D:\workspace\DiskNumber\src\com\tjn\test 然后运行javac TestDll.java 生成class文件后,需要生成头文件,输入
set classpath=D:\workspace\DiskNumber\src ,到项目的src根目录下,然后运行javah -jni com.tjn.test.TestDll,会生成一个
com_tjn_test_TestDll.h的文件,然后改头文件的名,我这里改为TestDll.h,需要和System.loadLibrary()中的名称相对应。如果不在项目里,单个文件运行当然没问题。但是在项目中生成头文件,需要如上进行操作,否则会报找不到类的错误。
5.可以看到生成的头文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_tjn_test_TestDll */
#ifndef _Included_com_tjn_test_TestDll
#define _Included_com_tjn_test_TestDll
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_tjn_test_TestDll
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_tjn_test_TestDll_add
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
这是javah根据java类自动生成的头文件,注释我们不管,可以看到里面的方法命名是Java_包名_类名_方法名,需要传递两个int类型的参数,在这个头文件中已经自动转换成jint类型。这个方法也没有任何的实现,相当于java中的接口,我们现在创建一个xx.c的文件来实现这里定义的方法。
JNIEXPORT jint JNICALL Java_com_tjn_test_TestDll_add
(JNIEnv *, jclass, jint x, jint y)
{
return x+y;
}
如何编译生成dll,这里就不加详述了。我这个例子是用vc++6.0做的.将生成的TestDll.dll文件放置到windows/system32中,然后在java类中调用就可以啦。
6.在java类的main函数中打印输出dll计算显示的返回结果
public static void main(String[] args) {
int r = TestDll.add(30,20);
System.out.println("result = "+r);
}
这里需要注意的是由于是用javah -jni 生成的头文件包含了包名,(从头文件生成的方法名就可以看出来),将这个Java类放置到其他路径下并能调用相应的dll文件,因为该dll文件只认定那个src路径下的com.tjn.test.TestDll类。所以在其他地方或者其他工程引用的话,需要将TestDll类打成jar包,在别的工程导入这个jar包,并做如下调用:
比如我在另外一个工程中的类main函数中调用
public static void main(String[] args) {
int a=com.tjn.test.TestDll.add(20, 50);
System.out.println(a);
}
调用jar包里面的方法,这是这个类就还在这个com.tjn.test的路径下,所以就不会报说找不到dll的异常啦!
JNative调用dll文件比JNI简单的多,改天整理后再说吧!也可以自己网上搜索,资料都差不多。
给个参考资料http://blog.youkuaiyun.com/pengchua/archive/2008/06/11/2534842.aspx
学习过程中的一些参考的相关资料:
1. http://www.blogjava.net/orangewhy/archive/2007/05/
2.http://www.iteye.com/topic/304594
3.http://yinxu.iteye.com/blog/206163
4.http://read.newbooks.com.cn/info/143806.html
以上这些是我在学习JNI过程中有碰到过的问题,记录一下,做个笔记,同时如果有碰到类似问题的朋友可以和我互相交流,一起学习,进步。