先介绍一下jni:Java Native Interface,它能够使java和其他编程语言编写的应用程序和库进行相互操作。
java中调用c函数,主要是通过本地化接口jni来实现的,在windows下,调用的是dll文件,在unix下,调用的是so文件。这里先介绍编写调用c函数的基本步骤:
(1):编写.java文件,其中c中的函数要用public native static修饰。
(2):编译.java文件为.class文件,使用javah生成.h文件。
(3):按照.h文件中的函数形式在c中实现函数。
(4):生成.dll文件,拷贝到java工程中。
(5):运行java文件。
注意以下几点:(1)如果java源文件放在包中,一定要在工程目录下使用javah命令。(2)在编写c函数时,要把jni.h和jni_md.h文件放在c的工程中。(3)在java文件中包含如下一句:static{System.loadLibrary("")},引号中为生成的动态连接库文件,不用加扩展名,系统会自动识别的。
JAVA调用DLL简单小例子
这个小例子用JNI调用了VC++做的DLL动态库。
1、总体说明:
实现一个函数,传入整形数i,返回值i*i,这个函数做在DLL中,java将通过JNI调用这个函数,传入一个参数,得到返回值。
确定DLL的名称为calldll.dll,函数shanfei(int i)。
2、编写java程序javacall.java,如下:
public class javacall
{
static
{
System.loadLibrary("calldll");
}
public native static int shanfei(int i);
public static void main(String[] args)
{
javacall jc = new javacall();
int j;
j = jc.shanfei(4);
System.out.println(j);
}
}
3、编译
javac javacall.java
4、生成头文件
javah javacall
生成javacall.h文件
5、制作VC++动态库
建立新DLL工程,程序中添加:
#include "javacall.h"
JNIEXPORT jint JNICALL Java_javacall_shanfei (JNIEnv *, jclass, jint p)
{
int j = p*p;
return j;
}
别忘了将javacall.h复制到VC工程目录中,然后编译,如果编译说找不到jni.h文件,可以将jni.h复制到工程目录中,还可将javacall.h文件中的#include <jni.h>改为#include "jni.h",再编译。
6、java调用
将生成的calldll.dll文件复制到javacall.java所在的目录中,运行
java javacall,应该可以看到运行结果。
注意可能发生以下几种情况:
1、当你做到第6步时,发现calldll一直不能装载,则将calldll.dll拷贝到windows\system32\ 下即可
2、当找不到jni.h时即提示错误(fatal error C1083: Cannot open include file: 'jni.h': No such file or directory将以下文件:)\jdk\include\jni.h\jdk\
include\win32\jawt_md.h\
jdk\include\win32\jni_md.h
将以上三个文件复制到Visual Studio.net的安装目录下的\Vc7\include目录中)
JNI 在编译Java文件时有时会爆JNI找不到类文件 一般是路径问题,环境问题等因素
我遇到的问题是路径问题,解决如下
D:\workspace\NDKDemo\src\com\jni\test 先要
cd D:\workspace\NDKDemo\src\com\jni\test 然后运行javac JniTest.java 生成class文件后,
需要生成头文件,输入
set classpath=D:\workspace\NDKDemo\src ,到项目的src根目录下,然后运行
javah -jni com.tjn.test.TestDll
c的同事给.so文件给我后,我放到Linux环境下进行测试,碰到了两个问题目前都已经解决,而且可以正常调用,给大家分享一下,
上面提到如果类带包名的话,执行的时候需要注意
1 需要将编译好的class放在包中,比如我执行时是将Test.class 放在com文件夹下的lzg 里面,在com的包外面执行Java com.lzg.Test 命令进行执行的
2 加载.so 文件时 ,我的c同事给我的.so 文件名为libswdes.so 我在java类里面调用时 需要这样写System.loadLibrary("swdes"); 不能带前面的lib和后缀名.so
3 需要将.so 放入到你的linux 下的jdk的安装目录下的 $JAVAHOME/jre/lib/i386 下
4 我在调用时碰到了一个jni wrong ELF class: ELFCLASS64 错误,不过顺利解决了由于同事编译.so时用了64位,而我的jdk是32位,解决办法是在编译.so 时指定位数 -m32(该步骤参考 http://blog.chinaunix.NET/uid-21335514-id-3286281.html)
补充:windows环境下.dll文件要放到 $JAVAHOME\jre\bin 下