jni全称Java Native Interface,中文为:Java本机接口,那这个到底是什么意思呢?
我们用一个例子来解释,你是一个维修工,你去客户家干活,你肯定会背一包工具,一般情况下,这么多工具肯定能解决99.99%的事情,但是今天你去的哪家他要维修天花板,过去的路程200公里,这种情况下,你不可能背着个梯子过去吧!你肯定是先电话和客户说你要准备个梯子,规格是什么,到了现场后拿上客户家的梯子,然后配合你的自己工具开始干活。
从上面的例子中,我们类推下,房顶就是程序处理的对象,现场就是系统,你就是程序处理流程,你带的工具在你背的包里面,可以理解成这个是自己的工具,所以叫程序方法。梯子是属于当地现场的,所以它是当地工具,以此类推,可以被称为本地方法。
所以这个本地可以理解成所在地,本地方法就是所在系统提供的方法。有些人会说jni是java调用c的方式,其实有问题的,应该是调用c编译出的链接库代码,所以说只要某语言生成的代码符合链接规范,能被java加载调用。
所以从这一点来看,你出门去干活和客户说,你要准备下梯子,规格是什么,就是提供定义信息(native方法的:完整类名、方法、参数)给对方,然后客户根据给的要求规格准备一个梯子,也就是要准备一个方法(命名为:Java_[完整名(点替换成下划线)]_方法名),你到现场拿到梯子,也就是加载了(System.load()),然后开始使用,也就是后面调用,当然你就可以像自己准备的方法一样调用了。
接下来我们做个例子:
创建一个java类:他要用到一个本地方法
//Math.java文件
public class Math {
static {
System.load("/usr/shitao/dev/c_java/tes/math.so");
}
public native int max(int i, int y);
public static void main(String[] args) {
System.out.println("max : " +
new Math().max(Integer.valueOf(args[0]), Integer.valueOf(args[1])));
}
}
然后我们根据前面要求的方式(Java_[完整名(点替换成下划线)]_方法名)创建本地方法实现
完整名:Math,方法名:max,那么就需要本地方法:Java_Math_max
//math.c文件
//env是jvm传过来的环境,obj是jvm调用对象,这两个作用可以反向调用java的方法和参数等。这里只是单向的java调用c,所以用万能指针顶着就好了,反正也用不上
int Java_Math_max(void **env, void *obj, int i, int j){
return (i>j)?i:j;
}
然后:
1.将math.c编译成公共库,用上面的话说就是:放到场地大家都可以用,变成一个本地的工具
gcc -I /usr/shitao/jdk1.8.0_161_linux/include -I /usr/shitao/jdk1.8.0_161_linux/include/linux -fPIC -shared -o ./math.so ./math.c
2.编译Math.java文件
javac Math.java
3.启动测试
java Math 1 2
上面两个文件就生产出了一个简单的jni例子
如果想要用到env,obj等规范,可以用javah等自动生成,参考例子: