JNI, Java Native Interface(Java本地接口).
JNI 是用於和本地 C 代碼進行交互操做的API。實際上能夠經過許多語言編寫,如C++、C#,本質上 Java 調用的是 dll/so 庫 。此處說是和本地 C 代碼互操做是由於 JNI API的支持。JNI API針對的是 C 語言,而不是Java。java
JNI 的出現的緣由有一些是爲了彌補一些沒法經過 Java 平臺實現的功能。好比 Windows 的註冊表,這是 Windows 獨有的東西,Java 並無現成能夠操做它的 API。後端
也有一些緣由是非 Java 語言編寫的代碼已經通過了大量的測試,無需從新用 Java 實現一套。bash
固然,最初也有 JVM 運行的比較慢的緣由,但隨着 JVM 的不斷髮展,Java編寫的代碼有時已經不遜於一些 C/C++ 的代碼了。函數
JNI 有着上述的一些好處,隨着而來的是它會帶來相應語言的缺點,
好比會引入 C 語言的無效指針形成的內存覆寫問題等等。工具
因此說 JNI 實際上使用範圍相對較窄,Web 後端方面用的比較少,安卓端用的相對更多一點。測試
如下爲一個簡單的示例編碼
首先在在 Java 中聲明 dll/so 庫中定義的函數。
聲明經過 native
關鍵字標識,提醒編譯器該方法在外部定義。指針
// 爲了簡單,此處沒有package public class HelloNative { public static native void greeting(); }
而後在 C 中定義函數,函數名有以下要求:code
\uoo7F
的 Unicode 字符,用 _0xxxx
來代替。xxxx
是該字符的Unicode值的4個十六進制數序列)爲了不在函數定義時候出錯,Java 提供了 javah
工具完成函數名的編寫操做。javah
是經過類文件來生成相應的文件的,因此源代碼必需要先編譯才能夠。接口
javah HelloNative
經過如上命令,會生成一個 HelloNative.h 的文件,這個文件包含了 greeting()
方法的聲明。
複製該文件,改成 .c 文件,去掉一些不須要的東西,而後包含 #include "HelloNative.h"
便可。
而後將方法聲明改成方法實現,在方法實現中編寫具體的代碼。
JNIEXPORT void JNICALL Java_HelloNative_greeting (JNIEnv* env, jclass cl) { printf("Hello Native World!"); }
以後就是編譯代碼了,此處僅粘貼我的測試過的命令,爲 Windows 上的 MinGW64 上的 gcc 。
gcc -I "jdk/include" -I "jdk/include/win32" -D __int64="long long" -shared -o HelloNative.dll HelloNative.c
關於 -D __int64="long long"
參數的說明:
Windows 上的 jni_md.h
含有聲明 typedef __int64 jlong;
,它專用於 cl 的。若是使用 gcc 須要設置 -D __int64="long long"
或者也能夠修改此文件,如:
#ifdef __GNUC__ typedef long long jlong; #else typedef __int64 jlong; #endif
建立 HelloNativeTest
類以供測試:
public class HelloNativeTest { static { // 此處不須要 dll/so 後綴,系統會自動根據系統不一樣換後綴 System.loadLibrary("HelloNative"); } public static void main(String[] args){ HelloNative.greeting(); } }
記住這裏打印的消息是經過 printf
打印的,不是 java 的代碼打印的。
注:
一些本地代碼的共享庫必須先運行初始化代碼,能夠將初始化代碼放置到JNI_OnLoad方法中,若是提供該方法,則虛擬機關
閉時會調用JNI_OnUnload方法,原型以下:
jint JNI_OnLoad(JavaVM* vm, void* reserved); //返回它所需的虛擬機的最低版本,如JNI_VERSION_1_2 void JNI_OnUnload(JavaVM* vm, void* reserved);