當前位置:編程學習大全網 - 編程語言 - java 加載動態鏈接庫怎麽使用相對路徑

java 加載動態鏈接庫怎麽使用相對路徑

對於java程序員來說,java語言的好處和優點,我想不用我說了,大家自然會說出很多壹套套的。但雖然我們作為java程序員,但我們不得不承認java語言也有壹些它本身的缺點。比如在性能、和底層打交道方面都有它的缺點。所以java就提供了壹些本地接口,他主要的作用就是提供壹個標準的方式讓java程序通過虛擬機與原生代碼進行交互,這也就是我們平常常說的java本地接口(JNI——java native Interface)。它使得在 Java 虛擬機(VM) 內部運行的Java 代碼能夠與用其它編程語言(如 C、C++ 和匯編語言)編寫的應用程序和庫進行互操作。JNI 最重要的好處是它沒有對底層 Java 虛擬機的實現施加任何限制。因此,Java虛擬機廠商可以在不影響虛擬機其它部分的情況下添加對JNI 的支持。程序員只需編寫壹種版本的本地應用程序或庫,就能夠與所有支持JNI 的Java 虛擬機協同工作。我們來看壹下為什麽要與原生代碼進行交互:

壹:提高應用程序性能。我們知道java對於c/c++、匯編語言來說,顯得比較“高級”。其實這裏的高級就是簡化了程序員的工作。很多底層的東西都讓java虛擬機做了。但畢竟相對於直接訪問底層來講,java多了壹步虛擬機的過程,所以在性能上比著這些原生語言稍微有點慢。

二:實現壹些與底層相關的功能。Java平臺提供的標準類庫,還有強大的API,雖然能完成大部分功能。但有些和底層硬件打交道的功能在java API提供的類庫中還是無法完成。

三:與已有的使用原生代碼編寫的程序進行集成。在於操作系統上由c或者c++等原生語言編寫的軟件進行集成的時候,可以用JNI。

JNI 接口函數和指針

平臺相關代碼是通過調用 JNI 函數來訪問Java 虛擬機功能的。JNI 函數可通過接口指針來獲得。接口指針是指針的指針,它指向壹個指針數組,而指針數組中的每個元素又指向壹個接口函數。每個接口函數都處在數組的某個預定偏移量中。下圖說明了接口指針的組織結構。

JNI 接口的組織類似於C++ 虛擬函數表或COM 接口。使用接口表而不使用硬性編入的函數表的好處是使JNI 名字空間與平臺相關代碼分開。虛擬機可以很容易地提供多個版本的JNI 函數表。例如,虛擬機可支持以下兩個JNI 函數表:

1)壹個表對非法參數進行全面檢查,適用於調試程序;

2)另壹個表只進行 JNI 規範所要求的最小程度的檢查,因此效率較高。

JNI 接口指針只在當前線程中有效。因此,本地方法不能將接口指針從壹個線程傳遞到另壹個線程中。實現 JNI 的虛擬機可將本地線程的數據分配和儲存在 JNI 接口指針所指向的區域中。

本地方法將JNI 接口指針當作參數來接受。虛擬機在從相同的 Java 線程中對本地方法進行多次調用時,保證傳遞給該本地方法的接口指針是相同的。但是,壹個本地方法可被不同的 Java 線程所調用,因此可以接受不同的 JNI 接口指針。

1)編寫Java類代碼

其中,需要JNI實現的方法應當用native關鍵字聲明,在該類中,用System.loadLibrary()方法加載需要的動態鏈接庫,關鍵代碼如下:

//Compute.java

public class Compute{

public native double sqrt(double params);

static{

//調用動態鏈接庫

System.loadLibrary("compute");

}

}

2)編譯成字節代碼

在這個過程中,由於采用了native關鍵字聲明,Java編譯器會忽視沒有代碼體的JNI方法部分。

3)生成相關JNI方法的頭文件

這個過程的實現壹般是通過利用jlavah-jni * class生成的(-jni可以省略),也可以手工生成該文件;但是由於 Java 虛擬機是根據壹定的命名規範完成對JNI方法的調用,所以手工編寫頭文件需要特別小心。

上述文件產生的頭文件部分代碼如下:

//Compute.h

extern“C”{

JNIEXPORT jdoubleJNICALL Java_Compute_comp(JNI-Env *, jobject, jdoubleArray);

JNI函數名稱分為三部分:首先是Java關鍵字,供Java虛擬機識別;然後是調用者類名稱(全限定的類名,其中用下劃線代替名稱分隔符);最後是對應的方法名稱,各段名稱之間用下劃線分割。

JNI函數的參數也由三部分組成:首先是JNIEnv *,是壹個指向JNI運行環境的指針;第二個參數隨本地方法是靜態還是非靜態而有所不同壹壹非靜態本地方法的第二個參數是對對象的引用,而靜態本地方法的第二個參數是對其Java類的引用;其余的參數對應通常Java方法的參數,參數類型需要根據壹定規則進行映射。

4)編寫相應方法的實現代碼

在編碼過程中,需要註意變量的長度問題,例如Java的整型變量長度為32位,而C語言為16位,所以要仔細核對變量類型映射表,防止在傳值過程中出現問題。

5)將JNI實現代碼編譯成動態鏈接庫

編譯過程是利用C/C++編譯器實現的,在windows平臺上,編譯和連接的結果是動態鏈接庫DLL文件。當要使用生成的動態鏈接庫時,調用者類中需要顯式調用該鏈接庫dll文件。

經過上述處理,基本上完成了壹個包含本地化方法的Java類的開發。

附錄:將Jav類型映射到本地C 類型

為了使用方便,特提供以下定義。

#define JNI_FALSE 0

#define JNI_TRUE 1

jsize 整數類型用於描述主要指數和大小:

typedef jint jsize;

故障排除

當使用 JNI 從Java 程序訪問本機代碼時,您會遇到許多問題。您會遇到的三個最常見的錯誤是:

1)無法找到動態鏈接。它所產生的錯誤消息是:java.lang.UnsatisfiedLinkError。這通常指無法找到***享庫,或者無法找到***享庫內特定的本機方法。

2)無法找到***享庫文件。當用 System.loadLibrary(String libname) 方法(參數是文件名)裝入庫文件時,請確保文件名拼寫正確以及沒有指定擴展名。還有,確保庫文件的位置在類路徑中,從而確保 JVM 可以訪問該庫文件。

3)無法找到具有指定說明的方法。確保您的 C/C++ 函數實現擁有與頭文件中的函數說明相同的說明。

結束語

從 Java 調用 C 或 C++ 本機代碼(雖然不簡單)是 Java 平臺中壹種良好集成的功能。雖然 JNI 支持 C 和 C++,但 C++ 接口更清晰壹些並且通常比 C 接口更可取。正如您已經看到的,調用 C 或 C++ 本機代碼需要賦予函數特殊的名稱,並創建***享庫文件。當利用現有代碼庫時,更改代碼通常是不可取的。要避免這壹點,在C++ 中,通常創建代理代碼或代理類,它們有專門的 JNI 所需的命名函數。然後,這些函數可以調用底層庫函數,這些庫函數的說明和實現保持不變。

  • 上一篇:語言證書是什麽?
  • 下一篇:什麽叫逆向設計,(工業方面的)
  • copyright 2024編程學習大全網