什么是JNI
The Java Native Interface (JNI) is a foreign function interface programming framework that enables Java code running in a Java virtual machine (JVM) to call and be called by native applications (programs specific to a hardware and operating system platform) and libraries written in other languages such as C, C++ and assembly.
Wiki
百科的解释。
简单来说就是Java
调用原生应用(硬件
和操作系统
级别)的接口。有一种说法是能不用就别用,原因很多,移植性,安全性,内存,线程等都会有很多挑战。
但是出于某些原因,我们没得选。来来来,我们挑战一下。
JNI的样例
-
新建一个
Java
类package com.uncledonghuang.jni; public class JniHello { /** * JNI say hello */ public static native void nativeSayHello(); }
-
生成
C++
头文件(如果您不知道什么头文件,可以尝试Google
一下;一般来说C++
头文件.h
声明类和函数,源文件.cpp
放置具体实现。表述不一定准确,C++
真的很难)javac -h . com/uncledonghuang/jni/JniHello.java
注意执行
javac
的工作目录,我们会看到生成的结果文件com_uncledonghuang_jni_JniHello.h
如下/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_uncledonghuang_jni_JniHello */ #ifndef _Included_com_uncledonghuang_jni_JniHello #define _Included_com_uncledonghuang_jni_JniHello #ifdef __cplusplus extern "C" { #endif /* * Class: com_uncledonghuang_jni_JniHello * Method: nativeSayHello * Signature: ()V */ JNIEXPORT void JNICALL Java_com_uncledonghuang_jni_JniHello_nativeSayHello (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
正如文件里的注释写的,为了避免麻烦,不要编辑这个文件。
-
添加实现文件
com_uncledonghuang_jni_JniHello.cpp
#include "com_uncledonghuang_jni_JniHello.h" #include <iostream> JNIEXPORT void JNICALL Java_com_uncledonghuang_jni_JniHello_nativeSayHello(JNIEnv *, jclass) { std::cout << "Hello from native C++ !!" << std::endl; }
-
编译
C++
源文件- macOS平台
g++ -c -fPIC -I${JAVA_HOME}/include \ -I${JAVA_HOME}/include/darwin \ com_uncledonghuang_jni_JniHello.cpp \ -o com_uncledonghuang_jni_JniHello.o
- Linux平台
g++ -c -fPIC -I${JAVA_HOME}/include \ -I${JAVA_HOME}/include/linux \ com_uncledonghuang_jni_JniHello.cpp \ -o com_uncledonghuang_jni_JniHello.o
- Window平台(没测试过)
g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 com_uncledonghuang_jni_JniHello.cpp -o com_uncledonghuang_jni_JniHello.o
-
链接
C++
共享库- macOS平台
g++ -dynamiclib -lc -o libJniHello.dylib com_uncledonghuang_jni_JniHello.o
- Linux平台
g++ -shared -fPIC -lc -o libJniHello.so com_uncledonghuang_jni_JniHello.o
- Window平台(没测试过)
g++ -shared -Wl,--add-stdcall-alias -o JniHello.dll com_uncledonghuang_jni_JniHello.o
-
加载动态链接库
有2种方式可以加载动态链接库,一种是加载库名
System.loadLibrary("JniHello");
这种方式可以加载动态链接库如
libJniHello.dylib
libJniHello.so
或JniHello.dll
还有一种方式是加载动态链接库文件,如
System.load("/usr/local/lib64/libJniHello.dylib");
可以根据需要使用不同的方式加载动态链接库。
修改
JniHello.java
加载动态链接库,增加main
方法,代码如下package com.uncledonghuang.jni; public class JniHello { static { System.loadLibrary("JniHello"); } public static void main(final String[] args) { JniHello.nativeSayHello(); } /** * JNI say hello */ public static native void nativeSayHello(); }
-
编译运行Java JNI
编辑Java
类
javac com/uncledonghuang/jni/JniHello.java
运行Java
类
java -cp . -Djava.library.path=. com.uncledonghuang.jni.JniHello
可以看到输出结果
Hello from native C++ !!