最近突然想去看看JNI,觉得这个东西很深奥,很强大。我们知道,Java Native Interface (JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI 是本地编程接口,它使得在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语言(如 C、C++ 和汇编语言)编写的应用程序和库进行交互操作。JNI的强大特性使我们在使用JAVA平台的同时,还可以重用原来的本地代码。作为虚拟机实现的一部分,JNI允许JAVA和本地代码间的双向交互。
上图标明了JNI的角色
JNI可以这样与本地程序进行交互:
1、 你可以使用JNI来实现“本地方法”(nativemethods),并在JAVA程序中调用它们。
2、 JNI支持一个“调用接口”(invocation interface),它允许你把一个JVM嵌入到本地程序中。本地程序可以链接一个实现了JVM的本地库,然后使用“调用接口”执行JAVA语言编写的软件模块。例如,一个用C语言写的浏览器可以在一个嵌入式JVM上面执行从网上下载下来的applets
下面就通过一个访问字段的小例子,体验体验JNI的强大。
JAVA支持两种field(字段),每一个对象的实例都有一个对象字段的复制;所有的对象共享一个类的静态字段。本地方法使用JNI提供的函数可以获取和修改这两种字段。先看一个从本地代码中访问对象字段的例子:
class InstanceFieldAccess {
public int s;
private native void accessField();
public static void main(String args[]) {
InstanceFieldAccess c = new InstanceFieldAccess();
c.s = 12;
c.accessField();
System.out.println("In Java:");
System.out.println(" c.s = \"" + c.s + "\"");
}
static {
System.loadLibrary("InstanceFieldAccess");
}
}
InstanceFieldAccess这个类定义了一个对象字段s。main方法创建了一个对象并设置s的值,然后调用本地方法InstanceFieldAccess.accessField在本地代码中打印s的值,并把它修改为一个新值。本地方法返回后,JAVA中把这个值再打印一次,可以看出来,字段s的值已经被改变了。下面是本地方法的实现:
#include "TestNative.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_InstanceFieldAccess_accessField(JNIEnv * env, jobject obj){
jclass native_clazz = (*env)->GetObjectClass(env,obj);
//得到jfieldID
jfieldID fieldID_num = (*env)->GetFieldID(env,native_clazz,"s","I");
//得到number属性
jint number= (*env)->GetIntField(env,obj,fieldID_num);
printf("In C: before number = %d\n",number);
//修改number属性的值
(*env)->SetIntField(env,obj,fieldID_num,18880L);
number= (*env)->GetIntField(env,obj,fieldID_num);
printf("In C: after number = %d\n",number);
}
下面是编译运行的过程: