本篇博客咱們將介紹Java中的一個關鍵字——native。java
native 關鍵字在 JDK 源碼中不少類中都有,在 Object.java類中,其 getClass() 方法、hashCode()方法、clone() 方法等等都是用 native 關鍵字修飾的。編程
public final native Class<?> getClass(); public native int hashCode(); protected native Object clone() throws CloneNotSupportedException;
那麼爲何要用 native 來修飾方法,這樣作有什麼用?windows
一、JNI:Java Native Interface
在介紹 native 以前,咱們先了解什麼是 JNI。安全
通常狀況下,咱們徹底可使用 Java 語言編寫程序,但某些狀況下,Java 可能會不知足應用程序的需求,或者是不能更好的知足需求,好比:oracle
①、標準的 Java 類庫不支持應用程序平臺所需的平臺相關功能。ide
②、咱們已經用另外一種語言編寫了一個類庫,如何用Java代碼調用?函數
③、某些運行次數特別多的方法代碼,爲了加快性能,咱們須要用更接近硬件的語言(好比彙編)編寫。post
上面這三種需求,其實說到底就是如何用 Java 代碼調用不一樣語言編寫的代碼。那麼 JNI 應運而生了。性能
從Java 1.1開始,Java Native Interface (JNI)標準就成爲java平臺的一部分,它容許Java代碼和其餘語言寫的代碼進行交互。JNI一開始是爲了本地已編譯語言,尤爲是C和C++而設計 的,可是它並不妨礙你使用其餘語言,只要調用約定受支持就能夠了。使用java與本地已編譯的代碼交互,一般會喪失平臺可移植性。可是,有些狀況下這樣作是能夠接受的,甚至是必須的,好比,使用一些舊的庫,與硬件、操做系統進行交互,或者爲了提升程序的性能。JNI標準至少保證本地代碼能工做在任何Java 虛擬機實現下。
經過 JNI,咱們就能夠經過 Java 程序(代碼)調用到操做系統相關的技術實現的庫函數,從而與其餘技術和系統交互,使用其餘技術實現的系統的功能;同時其餘技術和系統也能夠經過 JNI 提供的相應原生接口開調用 Java 應用系統內部實現的功能。
在windows系統上,通常可執行的應用程序都是基於 native 的PE結構,windows上的 JVM 也是基於native結構實現的。Java應用體系都是構建於 JVM 之上。
可能有人會問,Java不是跨平臺的嗎?若是用 JNI,那麼程序不就將失去跨平臺的優勢?確實是這樣的。
JNI 的缺點:
①、程序再也不跨平臺。要想跨平臺,必須在不一樣的系統環境下從新編譯本地語言部分。
②、程序再也不是絕對安全的,本地代碼的不當使用可能致使整個程序崩潰。一個通用規則是,你應該讓本地方法集中在少數幾個類當中。這樣就下降了JAVA和C之間的耦合性。
目前來說使用 JNI 的缺點相對於優勢仍是能夠接受的,可能後面隨着 Java 的技術發展,咱們不在須要 JNI,可是目前 JDK 仍是一直提供對 JNI 標準的支持。
三、用C語言編寫程序本地方法
上面講解了什麼是 JNI,那麼咱們接下來就寫個例子,如何用 Java 代碼調用本地的 C 程序。
官方文檔以下:https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html
步驟以下:
①、編寫帶有 native 聲明的方法的java類,生成.java文件;(注意這裏出現了 native 聲明的方法關鍵字)
②、使用 javac 命令編譯所編寫的java類,生成.class文件;
③、使用 javah -jni java類名 生成擴展名爲 h 的頭文件,也即生成.h文件;
④、使用C/C++(或者其餘編程想語言)實現本地方法,建立.h文件的實現,也就是建立.cpp文件實現.h文件中的方法;
⑤、將C/C++編寫的文件生成動態鏈接庫,生成dll文件;
下面咱們經過一個 HelloWorld 程序的調用來完成這幾個步驟。
注意:下面全部操做都是在全部操做都是在目錄:D:\JNI 下進行的。
1、編寫帶有 native 聲明的方法的java類
1 public class HelloJNI { 2 //native 關鍵字告訴 JVM 調用的是該方法在外部定義 3 private native void helloJNI(); 4 5 static{ 6 System.loadLibrary("helloJNI");//載入本地庫 7 } 8 public static void main(String[] args) { 9 HelloJNI jni = new HelloJNI(); 10 jni.helloJNI(); 11 } 12 13 }
用 native 聲明的方法表示告知 JVM 調用,該方法在外部定義,也就是咱們會用 C 語言去實現。
System.loadLibrary("helloJNI");加載動態庫,參數 helloJNI 是動態庫的名字。咱們能夠這樣理解:程序中的方法 helloJNI() 在程序中沒有實現,可是咱們下面要調用這個方法,怎麼辦呢?咱們就須要對這個方法進行初始化,因此用 static 代碼塊進行初始化。
這時候若是咱們直接運行該程序,會報「A Java Exception has occurred」錯誤:
2、使用 javac 命令編譯所編寫的java類,生成.class文件
執行上述命令後,生成 HelloJNI.class 文件:
3、使用 javah -jni java類名 生成擴展名爲 h 的頭文件
執行上述命令後,在 D:/JNI 目錄下多出了個 HelloJNI.h 文件:
4、使用C語言實現本地方法
若是不想安裝visual studio 的,咱們須要在 windows平臺安裝 gcc。
安裝教程以下:http://blog.csdn.net/altland/article/details/63252757
注意安裝版本的選擇,根據系統是32位仍是64位來選擇。64位點擊下載。
安裝完成以後注意配置環境變量,在 cmd 中輸入 g++ -v,若是出現以下信息,則安裝配置完成:
接着輸入以下命令:
gcc -m64 -Wl,--add-stdcall-alias -I"C:\Program Files\Java\jdk1.8.0_152\include" -I"C:\Program Files\Java\jdk1.8.0_152\include\include\win32" -shared -o helloJNI.dll helloJNI.c
-m64表示生成dll庫是64位的。後面的路徑表示本機安裝的JDK路徑。生成以後多了一個helloJNI.dll 文件
最後運行 HelloJNI:輸出 Hello JNI! 大功告成。
四、JNI調用C的流程圖
圖片引用自:https://www.cnblogs.com/Qian123/p/5702574.html
五、native關鍵字
經過上面介紹了那麼多JNI的知識,終於到介紹本篇文章的主角——native 關鍵字了。相信你們看完上面的介紹,應該也是知道什麼是 native 了吧。
native 用來修飾方法,用 native 聲明的方法表示告知 JVM 調用,該方法在外部定義,咱們能夠用任何語言去實現它。 簡單地講,一個native Method就是一個 Java 調用非 Java 代碼的接口。
native 語法:
①、修飾方法的位置必須在返回類型以前,和其他的方法控制符先後關係不受限制。
②、不能用 abstract 修飾,也沒有方法體,也沒有左右大括號。
③、返回值能夠是任意類型
咱們在平常編程中看到native修飾的方法,只須要知道這個方法的做用是什麼,至於別的就不用管了,操做系統會給咱們實現。
參考文檔:https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html
https://www.cnblogs.com/Qian123/p/5702574.html