国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

KVM的擴展

2019-11-18 16:19:50
字體:
來源:轉載
供稿:網友

KVM本身只帶有cldc1.1的類庫,功能十分簡單,不能滿足用戶的需求,本篇介紹如何對KVM進行擴展。

對KVM進行擴展,在java層十分簡單,只要向在編譯Java代碼時多加一個文件就可以,沒什么要說的,麻煩的是如果在加入的Java類中有本地操作該怎么辦?本地的C語言代碼放在哪里編譯才能夠供KVM調用?

答案是KNI。下面就以KNI為主要內容介紹如何對KVM加以擴展,在最后附加一個具體的實現例子。

1. KNI的特點:

KNI(K Native Interface)是SUN的KVM(K Virtual Machine)所使用的本地方法調用機制。

JNI(Java Native Interface)是已經為我們所熟悉的Java本地方法調用機制,JNI一般使用在J2SE或J2EE平臺上,本地方法被編進動態鏈接庫,在運行時由Java虛擬機載入。

KVM中也需要本地調用,但JNI是“重量級”的本地調用方式,在使用時消耗的資源較多,所以針對KVM設計出了KNI,KNI被稱為是JNI的一個簡化版,是“輕量級”的本地調用方式。KVM不能加載動態鏈接庫,所以在KNI機制下,本地方法不是寫在庫中,而是編入虛擬機內部。

以下是KNI與JNI最重要的一些區別:

KNI是“實現層”的API,即它是虛擬機實現的一部分,修改KNI的API就要重新編譯虛擬機,這些API的細節對于Java程序員來說是不可見的;而JNI的API是在運行時動態加載進來的,它的修改與虛擬機無關,JNI的API對于Java程序員來說是可見的。

KNI的函數建在虛擬機內部,只能為此虛擬機所獨享;而JNI的函數放在動態鏈接庫中,可以為多個虛擬機共用。

由于在虛擬機內部,KNI的很多操作方式與虛擬機有關,在傳遞參數和控制對象的時候都要先經過一些特別的處理;JNI的調用方式比較直接,但可能會增加安全隱患。

KNI是JNI的簡化版,功能也會弱一些,它不能創建對象,也不能調用Java層的方法。

總之,“在虛擬機內部”是KNI所有特點的根源,記得這一點,KNI的所有內容都非常容易理解。

下文各節對KNI的各個方面做一下介紹,只詳述那些KNI所特有的內容,更全面的內容可以參考KVM附帶的KNI specification。

2. 數據類型:

2.1 原始類型:


KVM的擴展(圖一)

上表中間一列是KNI所提供的8種原始類型,它們的長度與所對應的Java原始類型的長度相同。

2.2 對象類型:

KVM的擴展(圖二)

上圖是KNI所支持的對象類型,其實所有對象都可作為jobject,只是對圖中所示的這些object類的子類有特別的支持,比如為數組類提供了操作數組元素的方法。

2.3 返回類型:

KVM的擴展(圖三)

“返回類型”也就是本地方法的返回值的類型,KNI對它們有專門的定義。

上表右邊一列即本地方法的返回類型。

2.4 字符串類型、類描述符、字段描述符:


這三項內容都是在本地方法中對于Java層對象的描述,比如用”[Ljava/lang/String;”來描述String數組,這些內容與JNI規范以及Java虛擬機規范中所定義的都完全一致,所以這里不再多說。

3. KNI函數

本節分類簡介各種KNI函數的功能。大部分的函數功能比較容易理解,只有“參數傳遞”和“句柄操作”是比較特別的內容,將作詳細講解。

3.1 版本信息:

3.1.1 jint KNI_GetVersion()

得到KNI的版本號。

3.2 類和接口操作:

3.2.1 void KNI_FindClass(const char* name, jclass classHandle)

初始化一下指向某種對象的名柄,對象名字在name中。

3.2.2 void KNI_GetSuperClass(jclass classHandle, jclass superclassHandle)

取得超類的句柄。原類的句柄在classHandle中,調用后超類的名柄將被存放在superclassHandle中。如果classHandle指向一個java.lang.Object對象,則superclassHandle應為NULL。

3.3.3 jboolean KNI_IsAssignableFrom(jclass classHandle1, jclass classHandle2)

判斷classHandle1類的對象是否能安全轉換為classHandle2類的對象。

3.3 異常:

3.3.1 jint KNI_ThrowNew(const char* name, const char* message)

拋異常,name是異常類的名字,message是所附帶的信息。


3.3.2 void KNI_FatalError(const char* message)

出現致命錯誤時使用,向標準輸出打印出錯信息,并終止虛擬機。

3.4 對象操作

3.4.1 void KNI_GetObjectClass(jobject objectHandle, jclass classHandle)

取得某對象所對屬的類,objectHandle是對象句柄,調用后,類句柄將被存入classHandle中。

3.4.2 jboolean KNI_IsInstanceOf(jobject objectHandle, jclass classHandle)

判斷句柄objectHandle所指向的對象是否是句柄classHandle所指向的類的實例。

3.5 對象字段操作

3.5.1 jfieldID KNI_GetFieldID(jclass classHandle, const char* name, const char* signature)

取得類classHandle中由name和signature所指定的字段名。這個字段名的作用與JNI中的相同,是于在其它函數中讀寫字段的值。

3.5.2 <NativeType> KNI_Get<Type>Field(jobject objectHandle, jfieldID fieldID)

3.5.3 void KNI_Set<Type>Field(jobject objectHandle, jfieldID fieldID, <NativeType> value)

上面兩個方法分別用于讀寫<Type>類型字段的值,<Type>為基本類型。

3.5.4 void KNI_GetObjectField(jobject objectHandle, jfieldID fieldID, jobject toHandle)

3.5.5 void KNI_SetObjectField(jobject objectHandle, jfieldID fieldID, jobject fromHandle)


上面兩個方法分別用于讀寫對象。

3.6 靜態字段操作

3.6.1 jfieldID KNI_GetStaticFieldID(jclass classHandle, const char* name, const char* signature)

取得靜態字段名。

3.6.2 <NativeType> KNI_GetStatic<Type>Field(jclass classHandle, jfield fieldID)

3.6.3 void KNI_SetStatic<Type>Field(jclass classHandle, jfieldID fieldID, <NativeType>value)

上面兩個方法分別用于讀寫<Type>類型靜態字段的值,<Type>為基本類型。

3.6.4 void KNI_GetStaticObjectField(jclass classHandle, jfield fieldID, jobject toHandle)

3.6.5 void KNI_SetStaticObjectField(jclass classHandle, jfield fieldID, jobject fromHandle)

上面兩個方法分別用于讀寫靜態對象。

3.7 字符串操作

3.7.1 jsize KNI_GetStringLength(jstring stringHandle)

取得字符串長度。

3.7.2 void KNI_GetStringRegion(jstring stringHandle, jsize offset, jsize n, jchar* jcharbuf)

讀取字符串內容。

3.7.3 void KNI_NewString(const jchar* UChars, jsize length, jstring stringHandle)


使用Unicode序列創建String。

3.7.4 void KNI_NewStringUTF(const char* utf8chars, jstring stringHandle)

使用UTF-8序列創建String。

3.8 數組操作

3.8.1 jsize KNI_GetArrayLength(jarray arrayHandle)

取得數組長度。

3.8.2 <NativeType> KNI_Get<Type>ArrayElement(<ArrayType>arrayHandle, jint index)

取得<Type>類型數組元素。

3.8.3 void KNI_Set<Type>ArrayElement(<ArrayType>arrayHandle, jint index, <NativeType> value)

設置<Type>類型數組元素。

3.8.4 void KNI_GetObjectArrayElement(jobjectArray arrayHandle, jint index, jobject toHandle)

取得對象數組元素。

3.8.5 void KNI_SetObjectArrayElement(jobjectArray arrayHandle, jint index, jobject fromHandle)

設置對象數組元素。

3.8.6 void KNI_GetRawArrayRegion(jarray arrayHandle, jsize offset, jsize n, jbyte* dstBuffer)

以字節為單位讀取一個區域的值。

3.8.7 void KNI_SetRawArrayRegion(jarray arrayHandle, jsize offset, jsize n, const jbyte* srcBuffer)


以字節為單位設置一個區域的值。

3.9 參數傳遞

KNI的參數傳遞方式有一些不同的地方,在進行KNI調用時,從Java層傳來的參數在本地函數中不能直接讀取到。所有本地的函數,不論在Java層聲明時有多少個參數,它的參數表都將為空。這是因為KNI在虛擬機的內部,虛擬機在調用Java方法的時候是以堆棧的形式傳參的,在調用KNI方法的時候也是用了之種方式。

好在KNI的設計原則之一是“與虛擬機細節相隔離”,所以KNI的使用者不必去學習虛擬機的堆棧式傳參,KNI已經封裝好了一些方便使用的函數。

同樣,函數的返回值也要用專門的函數來傳回。

3.9.1 <ReturnType> KNI_GetParameterAs<Type>(jint index)

取得類型為<Type>的第index個參數,index是此參數在Java方法參數表中的位置。

比如:void native func (int i, long l, int j);這個Java方法有三個參數,在它的本地方法中,要得到它的第一個參數就要做如下調用:

KNI_GetParameterAsInt(1);

注意,long和double型的參數比較長,要占兩個位置,所以最后一個參數的序號不是3而是4。

3.9.2 void KNI_GetParameterAsObject(jint index, jobject toHandle)

同理,本函數讀取index處的對象,并使用toHandle句柄來索引它。

3.9.3 void KNI_GetThisPointer(jobject toHandle)

讀取當前類的this對象的句柄。

3.9.4 void KNI_GetClassPointer(jclass toHandle)

讀取當前類的句柄。

3.9.5 void KNI_ReturnVoid()

用于void型函數的返回。

3.9.6 void KNI_Return<Type>(<NativeType> value)


用于<Type>型函數的返回。

3.10 名柄操作

KNI中對于Java傳來的對象的引用,不能直接使用C語言的指針,這是因為KNI在虛擬機內部,C層的函數中所引用的對象也還是會參與垃圾收集,隨時有可能被移動,C層的指針指向的是絕對的內存位置,就會失效。所以KNI使用“句柄”來索引對象,句柄由虛擬機來維護,不會失效。

3.10.1 void KNI_StartHandles(n)

聲明在當前函數中所要使用的句柄數,要使用多少句柄,都需要事先聲明。

3.10.2 void KNI_DeclareHandle(handle)

聲明一個句柄。

3.10.3 jboolean KNI_IsNullHandle(handle)

判斷句柄是否為空。

3.10.4 jboolean KNI_IsSameObject(handle1, handle2)

判斷兩句柄是否指向了同一個對象。

3.10.5 void KNI_ReleaseHandle(handle)

釋放句柄。

3.10.6 void KNI_EndHandles()

刪除句柄。

3.10.7 void KNI_EndHandlesAndReturnObject(jobject objectHandle)

刪除句柄并把句柄所指向的對象作為函數值返回。

4. 實例:

以下是一個使用KNI擴展KVM的例子。


4.1 從http://www.sun.com/software/communitysource/j2me/cldc/download.xml下載KVM源程序;

4.2 java類庫源代碼放在j2me_cldc/api/src,在其中增加類rayman.test.KNITest,源文件如下:/* rayman/test/KNITest.java */
package rayman.test;

public class KNITest {
        public void PRintln(String s) {
                System.out.println(s);
        }
        public static native int nativeTest(int i, int j);
}

4.3 部分C層源文件放在j2me_cldc/kvm/VmCommon/src,新建文件nativeTest.c:/* nativeTest.c */
#include <kni.h>
#include <stdio.h>

KNIEXPORT KNI_RETURNTYPE_INT Java_rayman_test_KNITest_nativeTest() {
        jint i1 = KNI_GetParameterAsInt(1);
        jint i2 = KNI_GetParameterAsInt(2);
        printf("in function Java_rayman_test_KNITest_nativeTest() ");
        KNI_ReturnInt(i1+i2);
}

4.4 在j2me_cldc/kvm/VmUnix/build/Makefile中加入nativeTest.c。

4.5 在j2me_cldc/build/linux下執行make USE_KNI=true,編譯好的可執行文件kvm就在j2me_cldc/kvm/VmUnix/build下。

4.6 編寫測試類Hello:/* Hello.java */
import rayman.test.*;

public class Hello {
        public static void main(String [] args) {
                KNITest t=new KNITest();
                t.println("Hello KVM ! " + t.nativeTest(1,2));
        }
}

設置好classpath并執行,得到如期結果!

另外,在KNIspec.pdf文檔中有很多例子可供參考。

進入討論組討論。

(出處:http://m.survivalescaperooms.com)



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 土默特左旗| 灌南县| 胶州市| 延寿县| 陇川县| 闵行区| 灵寿县| 綦江县| 祁连县| 秦皇岛市| 宜阳县| 石阡县| 中卫市| 清涧县| 龙岩市| 湛江市| 平安县| 廉江市| 磴口县| 广饶县| 永善县| 渑池县| 岱山县| 碌曲县| 景德镇市| 元氏县| 文登市| 嘉义县| 莱芜市| 五原县| 栾川县| 泾阳县| 白山市| 黄平县| 襄汾县| 蓬安县| 陆良县| 宜黄县| 调兵山市| 江达县| 灌云县|