JNI是Java Native Interface的英文缩写, 中文翻译为本地调用, 自从Java 1.1开始就成为了Java标准的一部分.
C/C++是系统级的编程语言, 可以用来开发任何和系统相关的程序和类库, 但是Java本身编写底层的应用比较难实现, 使用JNI可以调用现有的本地库, 极大地灵活了Java的开发.
C/C++的效率是目前最好的语言, 可以使用C/C++来实现一些实时性非常高的部分. C/C++和Java本身都是非常流行的编程语言, 一些大型软件中经常使用语言之间的混合编程.
在Eclipse中新建项目JavaTest,新建包com.hisign.jni,新建类HelloJNI。代码如下
其中有一句比较重要, 这句话加载了动态类库。在windows下加载的就是.dll, 在linux下加载的就是.so。
System.loadLibrary(“HelloJNI2”);
package com.hisign.jni;
public class HelloJNI {
static{
System.loadLibrary("HelloJNI2");//加载生成的HelloJNI2.dll
}
public HelloJNI() {
}
public native void sayHello(String name);
}
在Eclipse中build项目,在bin目录下会生成HelloJNI.class文件。
HelloJNI编写好之后,即可在DOS环境下将HelloJNI.java编译为HelloJNI.h头文件。进入 cmd 命令行,使用上一步生成的 .class 文件,利用 jdk 的 javah 命令生成 *.h 头文件。
javah命令
-classpath : 文件所在的根路径
-d : 输出 *.h 头文件的路径
-jni : 生成JNI样式的包头文件,可以理解成 *.class 文件的 包路径+类名此处比较诡异的是,-classpath 必须得是.class 的包路径文件的上一级;-jni 必须是.class 文件的 包路径+类名,否则会报错。
使C++项目包含jdk 目录下的 jni.h 、 jni_md.h 以及之前生成的 com_hisign_jni_HelloJNI.h。这里有两种方法一种是把上述三个文件复制到C++项目的include文件夹(需要新建该文件夹)。然后
在C++项目的“包含目录”添加上include文件夹。第二种方法不用复制上述三个头文件,可以直接在C++项目的“包含目录”添加上上述三个头文件原本所在的文件夹。我偷懒使用了第二种方法,如下图
实现头文件方法,新建类c++文件test.cpp,代码如下
#include
#include
#include
JNIEXPORT void JNICALL Java_com_hisign_jni_HelloJNI_sayHello
(JNIEnv* env, jobject obj, jstring name){
const char* pname = env->GetStringUTFChars(name, NULL);
std::cout << "Hello," << pname <<std::endl;
}
build项目在x64/Debug目录下生成HelloJNI2.dll文件。
C++项目中有两个坑,如果不熟悉VS的朋友容易掉坑里
第一坑是有关于你使用的操作系统位数,如果是32位那么默认是在32位平台编译,没有任何问题。如果是64位那么需要在配置管理器中把平台改为64位。(如果先做了上述添加头文件的操作再修改平台 需要在修改平台后再次添加头文件)
在java项目下新建libs文件夹,把步骤3中生成的DLL文件复制进来。其实这个dll可以放在任何位置,但是需要配置Native library location, 配置位置在 工程属性->Java Build Path,配置Source标签或者Libraries标签下的Native library location都可以。