【詳解】JNI(Java Native Interface)(一)

前言:html

  一提到JNI,多數編程者會下意識地感覺到一種沒法言喻的恐懼。它給人的第一感受就是"難",由於它不是單純地在JVM環境內操做Java代碼,而是跳出虛擬機與其餘編程語言進行交互。java

  你可能至今還沒據說過這個技術,可是若是你是一個源碼愛好者,或者有翻閱過JDK的一些源碼,那你必定有接觸過native方法。你是否由於查閱源碼直到native方法戛然而止,但又因爲它的空方法體,而對底層原理不知因此? 本文就帶讓你瞭解JNI。並經過一些案例來本身實現JNI的交互。編程

什麼是JNI?windows

  JNI 全稱 Java Native Interface。Java本地方法接口,它是Java語言容許Java代碼與C、C++代碼交互的標準機制。維基百科是這樣解釋的:「當應用沒法徹底用Java編程語言實現的時候,(例如,標準Java類庫不支持的特定平臺特性或者程序庫時),JNI使得編程者可以編寫native方法來處理這種狀況」。這就意味着,在一個Java應用程序中,咱們可使用咱們須要的C++類庫,而且直接與Java代碼交互,並且在能夠被調用的C++程序內,反過來調用Java方法(回調函數)。編程語言

 

JNI的優勢函數

  (1)JNI使得一些"過程"無需在Java中實現。例如,硬件敏感的,或者直接與操做系統API關聯的命令。工具

  (2)因爲使用底層的庫,如圖形,計算,各類類型的渲染等等,能夠提升應用的運行性能。性能

  (3)已經有大量的庫已經被實現,編程者可直接使用,不用再自行編寫。這裏的庫指的是用其餘編程語言實現的程序庫,例如IO流或者線程等底層與OS交互的操做都是由C/C++實現的。spa

 

具體實現原理操作系統

  交互模式如圖

  

 

要從Java調用C++函數,你須要進行如下操做: 

  1. 在Java類中建立一個native方法,此方法被本類其餘方法調用

        

  2. 建立一個頭文件,能夠利用javah命令生成。

      在頭文件中定義它的簽名,以下所示:

  

  接口規範:

  JNIEXPORT <返回類型> JNICALL Java_<包名>_<類名>_<方法名>(JNIEnv*, <原對象引用>,<參數1>..<參數n>)

  • extern "C" 只被C++編譯器識別,標明此方法利用C的函數命名協議來編譯。
  • JNIEXPORT 是JNI必要的修飾符。
  • 數據類型帶有"j"前綴的:jdouble,jobject..等是Java對象或類型在C++中的映射
  • JNIEnv* 指向JNI 環境,能夠利用其調用全部JNI函數
  • jobject 引用當前Java對象

  3. 建立一個源文件,實現頭文件中定義的接口。實現內容就是Java代碼調用的C/C++代碼。

  4. 編譯頭文件和源文件生成C/C++動態連接庫 .so/.dll 文件

  5. 此native方法所在類,加載動態連接庫。由於加載連接庫要在執行native方法以前,因此此加載過程通常放在靜態初始化塊內執行。

   

  或

  

  總結一下,從Java代碼中調用C/C++代碼的流程

  (1)建立一個有native標識的方法,而且從其餘Java方法調用它

  (2)Java編譯器生成字節碼

  (3)C/C++ 編譯器生成動態庫  .so文件(Linux)或 .dll文件(Windows)

  (4)運行程序,執行字節碼

  (5)執行到loadLibary或load調用的時候,添加一個 .so文件到這個進程中

  (6)執行到native方法的時候,經過方法簽名,在已打開的.so文件中進行搜索。

  (7)若是連接庫內有對應方法,就會被執行,不然程序崩潰

  注:因爲windows沒找到生成動態連接庫的工具,又不想安裝C/C++開發環境,故如下案例都在以CentOS爲操做系統的虛擬機內運行

  案例一:從Java調用C代碼輸出Hello World   

  此案例全部生成的全部文件以下:

  

  (1)建立JNI文件夾,建立Java文件以下:

  

  這裏,咱們定義了一個native方法,是個空方法體,咱們在主函數內對其進行調用。

  注:這裏使用的是System.load從絕對路徑引用動態連接庫,固然也可使用loadLibrary方法,其是從java.library.path對應路徑下搜索對應名稱的庫文件並加載。

  (2)編譯HelloJNI.java文件,生成類文件

  

  (3)利用JDK提供的JNI命令工具,javah生成 .h頭文件。

  

  注:發現Linux環境下,javah竟然不能從當前文件夾掃描到類文件,須要指定類路徑 其中 -cp 就是-classpath

  如下是利用javah生成的頭文件。

  

  (4)建立HelloJNI.c文件,編寫實現體

  

  (5)利用gcc生成動態連接庫,注意咱們這裏有引用到jni.h這個頭文件,此文件由JDK提供,另外jni.h還引用了jni_md.h這個文件。必須引入這兩個頭文件,才能經過編譯。

  兩個文件的所在地,本人JDK的安裝路徑在/usr/java下,每一個人可能都不同。

  

  

  在gcc命令內經過指定( -I 路徑 )引入庫所在的目錄,利用前面前面的頭文件和源文件編譯成動態連接庫 hello.so

  

  

  (6)運行java程序

  

  由圖可知,咱們成功調用了C的代碼

相關文章
相關標籤/搜索