常州做网站哪家快,美橙互联旗下网站,公司名称大全集,国家653建筑工程网我们知道Java本身的实现#xff0c;很大一部分是用C写的。实际上#xff0c;Java也允许我们和原生平台的代码进行交互。
Java定义了一个接口规范#xff0c;就叫做Java Native Interface#xff0c;通过这个接口规范#xff0c;我们就可以让Java代码运行原生平台的代码。…我们知道Java本身的实现很大一部分是用C写的。实际上Java也允许我们和原生平台的代码进行交互。
Java定义了一个接口规范就叫做Java Native Interface通过这个接口规范我们就可以让Java代码运行原生平台的代码。
首先写一个Java的Class1
public class HelloJNI {static {System.loadLibrary(hello); // Load native library at runtime// hello.dll (Windows) or libhello.so (Unixes)}// Declare a native method sayHello() that receives nothing and returns voidprivate native void sayHello();// Test Driverpublic static void main(String[] args) {new HelloJNI().sayHello(); // invoke the native method}
}从上面的代码我们看到一些平常写Java代码的时候不常看见的东西首先是这个 System.loadLibrary(hello);这个System.loadLibrary方法可以用来调用平台的原生库。然后是这个
private native void sayHello();这个native关键字意味着这个代码的实现是原生平台实现而不是Java代码。因此我们要做一个hello库提供这个sayHello方法。
接下来我们用javah命令生成.h文件
$ ls HelloJNI.java
HelloJNI.java
$ javah HelloJNI
$ ls *.h
HelloJNI.h我们得到了HelloJNI.h文件它的内容是根据HelloJNI.java生成的我们看看里面的内容
/* DO NOT EDIT THIS FILE - it is machine generated */
#include jni.h
/* Header for class HelloJNI */#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern C {
#endif
/** Class: HelloJNI* Method: sayHello* Signature: ()V*/
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *, jobject);#ifdef __cplusplus
}
#endif
#endif可以看到上面的文件里自动生成了JNI接口规范的一些约定代码。比如jni.h这个是由JDK提供的我们稍后要引用。还有sayHello对应的C/C的方法是Java_HelloJNI_sayHello这个命名方式可以看出来是Java_ClassName_MethodName这个也是JNI的约定。
接下来我们写一个HelloJNI.c来实现这个HelloJNI.h
#include jni.h
#include stdio.h
#include HelloJNI.h// Implementation of native method sayHello() of HelloJNI class
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {printf(Hello World!\n);return;
}这个代码就非常简单就是实现了Java_HelloJNI_sayHello功能就是printf(Hello World!\n);。我们编译这个代码
$ c -c -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin HelloJNI.c注意我是在MacOS上编译所以引用的是MacOS的JDK的include目录此外MacOS的内核名叫darwin你如果用Linux系统你的JDK的include目录里应该有一个linux目录对应上面的darwin目录。
这两个-I主要是为了引用JNI相关的库文件
$ ls $JAVA_HOME/include/jni*
/Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home/include/jni.h$ ls $JAVA_HOME/include/darwin/jni*
/Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home/include/darwin/jni_md.h这两个.h文件是必须的。编译完成后我们就得到了object文件
$ ls *.o
HelloJNI.o用nm命令看一下这个object file里面的符号
$ nm HelloJNI.o
0000000000000000 T _Java_HelloJNI_sayHelloU _printf可以看到包含的的methods。我们要把这个object文件链接成library在MacOS下命令如下
$ c -dynamiclib -o libhello.jnilib HelloJNI.o这样我们就得到了Java可以调用的libhello.jnilib
$ ls *.jnilib
libhello.jnilib我们在Java代码里写的是System.loadLibrary(hello)但是这里的library名字叫做libhello前面多了lib这是一种命名约定。
如果你在Linux系统下生成library的命令不太一样需要用下面的命令生成.so文件也就是shared library文件
cc -shared -fpic -o libhello.so -I/usr/java/include -I/usr/java/include/linux HelloJNI.c接下来就是编译Java代码
$ javac HelloJNI.java我们得到class文件
$ ls *.class
HelloJNI.class此时目录里应该有我们的library还有class文件
$ ls *.class *.jnilib
HelloJNI.class libhello.jnilib此时我们可以使用java命令运行HelloJNI.class
$ java HelloJNI
Hello World!可以看到我们这个Hello World!字符串是来自于native method的Java_HelloJNI_sayHello里面的printf。我们的Java代码与原生平台进行了交互。
参考资料 https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.htm