JAVA 本机接口(JAVA native interface) JNI 是一个编程接口;
什么场合下应该使用JNI
当你开始着手准备一个使用JNI的项目时,请确认是否还有替代方案。应用程序使用JNI会带来一些副作用。下面给出几个方案,可以避免使用JNI的时候,达到与本地代码进行交互的效果:
2、当用JAVA程序连接本地数据库时,使用
JDBC提供的API。
3、JAVA程序可以使用分布式对象技术,如JAVA
IDL API。
这些方案的共同点是,JAVA和C处于不同的线程,或者不同的机器上。这样,当本地程序崩溃时,不会影响到JAVA程序。
下面这些场合中,同一进程内JNI的使用无法避免:
1、程序当中用到了JAVA API不提供的特殊系统环境才会有的特征。而跨进程操作又不现实。
2、你可能想访问一些己有的本地库,但又不想付出跨进程调用时的代价,如效率,内存,数据传递方面。
3、JAVA程序当中的一部分代码对效率要求非常高,如算法计算,图形渲染等。
总之,只有当你必须在同一进程中调用本地代码时,再使用JNI。
缺点
1、程序不再
跨平台。要想跨平台,必须在不同的系统环境下重新编译本地语言部分。
编程,来举个栗子:helloworld
一、
编写Java代码:
public class Helloworld {
// 使用C 或C++ 实现输出
public native void sayHello();
public static void main(String[] args) {
System.loadLibrary("mydll");
new Helloworld().sayHello();
}
}
使用javah.exe (命令在JDK bin目录下)生成头文件 ;
javah [-classpath class目录] 全类名 [-d 输出目录]//生成头文件
也可cd 到class目录下 javah 全类名 缺省生成,在class 目录下生成
二、使用vs新建dll 动态链接库项目
然后把生成头文件拷贝到VS 源码目录,一定要在文件夹上拷贝,不能直接粘贴到VS 上;
然后在vs源码上右键添加文件;
然后再拷贝jdk 下include目录下的jni.h 以及win32目录下的jni_md.h 文件到 VS项目源码目录下,按照上一步添加到源码
把jni.h中的依赖修改成双引号<jni_md.h> 改成 “jni_md.h”,以及hello头文件的jni也要修改
然后变下cpp文件,编写代码:
三、编译打包 针对运行的虚拟机 选择32位还是64位,我是64系统的所以选择64,默认是32位的,故编64位的记得设置
在解决方案的目录下 会生成dell目录 下生成dll(是解决方案目录,不项目目录),如果是设置release会生成 x64目录下生成dll
四、java调用dll 中的方法;
//
public class Helloworld {
// 使用C 或C++ 实现输出
public native void sayHello();
public static void main(String[] args) {
//
/**
* java调用dll文件,那就要让java知道有dll的存在,网上很多说直接把vs生成dll目录加入path目录,
* 经我测试这个方法是不可取的,因为java的运行path并不和系统的path值一致,可能因系统而异,
* 检验方法,在runtime对象找path,确认dll是否在其中path目录
*
* Properties properties = System.getProperties();
* String path = properties.getProperty("PATH");
* Map<String, String> evn = System.getenv();
*
* 直接拷贝dll到系统的C:\Windows\System32 目录下是没问的,这个是系统默认运行目录,找不到目录的,使用上述代码运行查找原因
*
*
*
*/
System.loadLibrary("mydll");
// System.load("路径/mydll.dll");
//使用文件路径加载,不过dll在不在path目录下,可直接加载,建议使用这个方法,修改之后不用拷贝dll,直接运行
new Helloworld().sayHello();
/**
* 顺带说明下 System.load 与 System.loadLibrary
* 功能 :两个方法都是去加载dll库,
* 区别 :System.load 根据文件目录和名称加载dll,
* System.loadLibrary 是加载已知运行Path目录下的dll库,并且不能带后缀,
其实起运行的时候System.load 与 System.loadLibrary调用了 : ClassLoader.loadLibrary(fromClass, filename, true);
*
*/
}
}