Java中native方法

來源:互聯網
上載者:User

Java不是完美的,Java的不足除了體現在運行速度上要比傳統的C++慢許多之外,Java無法直接存取到作業系統底層(如系統硬體等),為此Java使用native方法來擴充Java程式的功能。

什麼是Native Method?簡單地講,一個Native Method就是一個java調用非java代碼的介面。

一個Native Method是這樣一個java的方法:該方法的實現由非java語言實現,比如C。這個特徵並非java所特有,很多其它的程式設計語言都有這一機制,比如在C++中,你可以用extern "C"告知C++編譯器去調用一個C的函數。

 "A native method is a Java method whose implementation is provided by non-java code."
在定義一個native method時,並不提供實現體(有些像定義一個java interface),因為其實現體是由非java語言在外面實現的。

例如,可以將native方法比作Java程式同C程式的介面,其實現步驟如下:

1、在Java中聲明native()方法,然後編譯;
2、用javah產生一個.h檔案;
3、寫一個.c檔案實現native匯出方法,其中需要包含第二步產生的.h檔案(注意其中又包含了JDK帶的jni.h檔案);
4、將第三步的.c檔案編譯成動態連結程式庫檔案;
5、在Java中用System.loadLibrary()方法載入第四步產生的動態連結程式庫檔案,這個native()方法就可以在Java中被訪問了。

JAVA本地方法適用的情況如下:

1、為了使用底層的主機平台的某個特性,而這個特性不能通過JAVA API訪問
2、為了訪問一個老的系統或者使用一個已有的庫,而這個系統或這個庫不是用JAVA編寫的
3、為了加快程式的效能,而將一段時間敏感的代碼作為本地方法實現。

首先寫好JAVA檔案

package com.hode.hodeframework.modelupdate; public class CheckFile {   public native void displayHelloWorld();   static {       System.loadLibrary("test");   }   public static void main(String[] args) {       new CheckFile().displayHelloWorld();   } } 

然後根據寫好的檔案編譯成CLASS檔案;

然後在classes或bin之類的class根目錄下執行javah -jni com.hode.hodeframework.modelupdate.CheckFile,就會在根目錄下得到一個com_hode_hodeframework_modelupdate_CheckFile.h的檔案

然後根據標頭檔的內容編寫com_hode_hodeframework_modelupdate_CheckFile.c檔案

#include "CheckFile.h" #include #include JNIEXPORT void JNICALL Java_com_hode_hodeframework_modelupdate_CheckFile_displayHelloWorld(JNIEnv *env, jobject obj) {   printf("Hello world!\n");   return; } 

之後編譯產生DLL檔案如“test.dll”,名稱與System.loadLibrary("test")中的名稱一致

vc的編譯方法:cl -I%java_home%\include -I%java_home%\include\win32 -LD com_hode_hodeframework_modelupdate_CheckFile.c -Fetest.dll

最後在運行時加參數-Djava.library.path=[dll存放的路徑]

 

變數按照以下修飾符的順序進行定義

1.     public

2.     protected

3.     private

4.     abstract

5.     static

6.     final

7.     transient

8.     volatile

9.     synchronized

10.  native

11.  strictfp

 

1.     Class (static) variables. First the public class variables, then the protected, then package level (no access modifier), and then the private.

2.     Instance variables. First the public class variables, then the protected, then package level (no access modifier), and then the private.

3.     Constructors

4.     Methods

標識符native可以與所有其它的java標識符連用,但是abstract除外。這是合理的,因為native暗示這些方法是有實現體的,只不過這些實現體是非java的,但是abstract卻顯式地指明這些方法無實現體。native與其它java標識符連用時,其意義同非Native Method並無差別,比如native static表明這個方法可以在不產生類的執行個體時直接調用,這非常方便,比如當你想用一個native method去調用一個C的類庫時。再比如native synchronized,JVM在進入這個方法的實現體之前會執行同步鎖機制(就像java的多線程)。

一個native method方法可以返回任何java類型,包括非基本類型,而且同樣可以進行異常控制。這些方法的實現體可以製造一個異常並且將其拋出,這一點與java的方法非常相似。當一個native method接收到一些非基本類型時如Object或一個整型數組時,這個方法可以訪問這些非基本類型的內部,但是這將使這個native方法依賴於你所訪問的java類的實現。有一點要牢牢記住:我們可以在一個native method的本地實現中訪問所有的java特性,但是這要依賴於你所訪問的java特性的實現,而且這樣做遠遠不如在java語言中使用那些特性方便和容易。

native method的存在並不會對其他類調用這些本地方法產生任何影響,實際上調用這些方法的其他類甚至不知道它所調用的是一個本地方法。JVM將控制調用本地方法的所有細節。需要注意當我們將一個本地方法聲明為final的情況。用java實現的方法體在被編譯時間可能會因為內聯而產生效率上的提升,但是一個native final方法是否也能獲得這樣的好處卻是值得懷疑的,但是這隻是一個代碼最佳化方面的問題,對功能實現沒有影響。

如果一個含有本地方法的類被繼承,子類會繼承這個本地方法並且可以用java語言重寫這個方法(這個似乎看起來有些奇怪),同樣的如果一個本地方法被final標識,它被繼承後不能被重寫。
本地方法非常有用,因為它有效地擴充了JVM。事實上,我們所寫的java代碼已經用到了本地方法,在sun的java的並發(多線程)的機制實現中,許多與作業系統的接觸點都用到了本地方法,這使得java程式能夠超越java運行時的界限。有了本地方法,java程式可以做任何應用程式層次的任務。

為什麼要使用Native Method

java使用起來非常方便,然而有些層次的任務用java實現起來不容易,或者我們對程式的效率很在意時,問題就來了。
1. 與java環境外互動:
   有時java應用需要與java外面的環境互動。這是本地方法存在的主要原因,你可以想想java需要與一些底層系統如作業系統或某些硬體交換資訊時的情況。本地方法正是這樣一種交流機制:它為我們提供了一個非常簡潔的介面,而且我們無需去瞭解java應用之外的繁瑣的細節。
2. 與作業系統互動:
   JVM支援著java語言本身和執行階段程式庫,它是java程式賴以生存的平台,它由一個解譯器(解釋位元組碼)和一些串連到本地代碼的庫組成。然而不管怎樣,它畢竟不是一個完整的系統,它經常依賴於一些底層(underneath在下面的)系統的支援。這些底層系統常常是強大的作業系統。通過使用本地方法,我們得以用java實現了jre與底層系統的互動,甚至JVM的一些部分就是用C寫的,還有,如果我們要使用一些java語言本身沒有提供封裝的作業系統的特性時,我們也需要使用本地方法。
3. Sun's Java
    Sun的解譯器是用C實現的,這使得它能像一些普通的C一樣與外部互動。jre大部分是用java實現的,它也通過一些本地方法與外界互動。例如:類java.lang.Thread 的 setPriority()方法是用java實現的,但是它實現調用的是該類裡的本地方法setPriority0()。這個本地方法是用C實現的,並被植入JVM內部,在Windows 95的平台上,這個本地方法最終將調用Win32 SetPriority() API。這個本地方法的具體實現由JVM直接提供,但更多的情況是本地方法由外部的動態連結程式庫(external
dynamic link library)提供,然後被JVM調用。

JVM怎樣使Native Method跑起來

我們知道,當一個類第一次被使用到時,這個類的位元組碼會被載入到記憶體,並且只會載入一次。在這個被載入的位元組碼的入口維持著一個該類所有方法描述符的list,這些方法描述符包含這樣一些資訊:方法代碼存於何處,它有哪些參數,方法的描述符(public之類)等等。

如果一個方法描述符內有native,這個描述符塊將有一個指向該方法的實現的指標。這些實現在一些DLL檔案內,但是它們會被作業系統載入到java程式的地址空間。當一個帶有本地方法的類被載入時,其相關的DLL並未被載入,因此指向方法實現的指標並不會被設定。當本地方法被調用之前,這些DLL才會被載入,這是通過調用java.system.loadLibrary()實現的。

最後需要提示的是,使用本地方法是有開銷的,它喪失了java的很多好處。如果別無選擇,我們可以選擇使用本地方法。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.