小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

java本地接口調(diào)用(篇二)

 quandsu 2013-06-25

c/c++本地代碼中訪問javaString對(duì)象

.java中,使用的字符串String對(duì)象是Unicode碼,即每個(gè)字符不論是中文還是英文或是符號(hào),一個(gè)字符總是占用兩個(gè)字節(jié)。

c/c++本地代碼中創(chuàng)建javaString對(duì)象

.java通過JNI接口可以將java的字符串轉(zhuǎn)換到c/c++中的寬字符串(wchar_t *),或是傳回一個(gè)UTF-8的字符串(char *)到c/c++。反過來,c/c++可以通過一個(gè)寬字符串,或是一個(gè)UTF-8編碼的字符串來創(chuàng)建一個(gè)java端的String對(duì)象。

GetStringChars/GetStringUTFChars

.這兩個(gè)函數(shù)用來取得與某個(gè)jstring對(duì)象相關(guān)的java字符串。分別可以取得UTF-16編碼的寬字符串(jchar*)跟UTF-8編碼的字符串(char*。

Const jchar* GetStringChars(jstring str, jboolean* copied)

Const char* GetStringUTFChars(jstring str, jboolean* copied)

第一個(gè)參數(shù)傳入一個(gè)指向java中的String對(duì)象的jstring變量

第二個(gè)參數(shù)傳入的是一個(gè)jboolean的指針。

這兩個(gè)函數(shù)分別都會(huì)有兩個(gè)不同的動(dòng)作:

第一個(gè)參數(shù):

1、 開新內(nèi)存,然后把java中的String拷貝到這個(gè)內(nèi)存中,然后返回這個(gè)內(nèi)存地址的指針。

2、 直接返回指向javastring的內(nèi)存的指針,這個(gè)時(shí)候千萬不要改變這個(gè)內(nèi)存的內(nèi)容,這將破壞Stringjava中始終是常量這個(gè)原則。

第二個(gè)參數(shù):是用來標(biāo)示是否對(duì)javastring對(duì)象進(jìn)行了拷貝的。

如果傳入的這個(gè)jboolean指針不是null,則他會(huì)給該指針指向的內(nèi)存?zhèn)魅?/span>JNI_TRUEJNI_FALSE標(biāo)示是否進(jìn)行了拷貝。

傳入null標(biāo)示不關(guān)心是否拷貝字符串,它就不會(huì)給jboolean*指向的內(nèi)存賦值。

使用這兩個(gè)函數(shù)取得的字符串,在不使用的時(shí)候,要使用ReleaseStringChars/ReleaseStringUTFChars來釋放拷貝的內(nèi)存,或是釋放對(duì)javaString對(duì)象的引用。

ReleaseStringChars(jstring jstr, const jchar* str);

ReleaseStringUTFChars(jstring jstr, const char* str);

第一個(gè)參數(shù)指定一個(gè)jstring變量,即是要釋放的本地字符串的來源。

第二個(gè)參數(shù)就是要釋放的本地字符串

GetStringCritical:是為了增加直接傳回指向java字符串的指針的可能性(而不是拷貝),jdk1.2出來了新的函數(shù):GetStringCritical/ReleaseStringCritical。

Const jchar* GetStringCritical(jstring str, jboolean* copied)

Void realeaseStringCritical(jstring jstr, const jchar* str);

GetStringCritical/RealeaseStringCritical之間是一個(gè)關(guān)鍵區(qū)。在這關(guān)鍵區(qū)之中絕對(duì)不能呼叫JNI的其他函數(shù)和會(huì)造成當(dāng)前線程中斷或是會(huì)讓當(dāng)前線程等待的任何本地代碼,否則將造成關(guān)鍵區(qū)代碼執(zhí)行區(qū)間垃圾回收器停止運(yùn)作,任何觸發(fā)垃圾回收器的線程也會(huì)暫停。其他的觸發(fā)垃圾回收器的線程不能前進(jìn)直到當(dāng)前線程結(jié)束而激活垃圾回收器。

在關(guān)鍵區(qū)中千萬不雅出現(xiàn)中斷操作,或是在jvm中分配任何新對(duì)象。否則會(huì)造成jvm死鎖。

雖說這個(gè)函數(shù)會(huì)增加直接傳回指向java字符串的指針的可能性,不過還是會(huì)根據(jù)情況傳回拷貝過的字符串。

不支持GetStringUTFCritical,沒有這樣的函數(shù)。由于java字符串用的是UTF16,要轉(zhuǎn)成UTF8編碼的字符串始終需要進(jìn)行一個(gè)拷貝。所以沒有這樣的函數(shù)。

GetStringRegion/GetStringUTFRegion

.java1.2出來的函數(shù),這個(gè)函數(shù)的動(dòng)作,是把java字符串的內(nèi)容直接拷貝到c/c++的字符數(shù)組中。在呼叫這個(gè)函數(shù)之前必須有一個(gè)c/c++分配出來的字符串,然后傳入到這個(gè)函數(shù)中進(jìn)行字符串的拷貝。

由于c/c++中分配內(nèi)存開銷相對(duì)小,而且java中的String內(nèi)容拷貝的開銷可以忽略,更好的一點(diǎn)是此函數(shù)不分配內(nèi)存,不會(huì)拋出OutOfMemoeryError異常。

//拷貝java字符串并以UTF-8編碼傳入buffer.

GetStringUTFRegion(String str, jsize start, jsize len, char* buffer);

//拷貝java字符串并以UTF-16編碼傳入buffer

GetStringRegion(jstring str, jsize start, jsize len, jchar* buffer);

其他的字符串函數(shù):

.jstring NewString(const jchar* str, jszie len); 寬字符串(c/c++中的普通的字符串)

.jstring NewStringUTF(const char* str);

.jsize GetStringLength(jstring str);

.jsize GetStringUTFLength(jstring str);

例如:紅線圈住的是對(duì)應(yīng)的方法應(yīng)用。Message是定義在java類中,在此省略了代碼

 

處理數(shù)組:數(shù)組分為兩種(基本類型的數(shù)組、對(duì)象類型的數(shù)組)

一個(gè)能通用于兩種不同類型數(shù)組的函數(shù):GetArrayLength(jarray array)

處理--基本類型的數(shù)組:

.處理基本類型的數(shù)組跟處理字符串類似,也有很相似的函數(shù)。

.Get<TYPE>ArrayElements(<TYPE>Array arr, jboolean* isCopied);這類的函數(shù)可以把java基本類型的數(shù)組轉(zhuǎn)換到c/c++中的數(shù)組。有兩種處理方式,一是拷貝一份傳回本地代碼,另一個(gè)是把指向java數(shù)組的指針傳回到本地代碼。處理完本地化的數(shù)組后,通過Release<TYPE>ArrayElements來釋放數(shù)組。

.Release<TYPE>ArrayElements(<TYPE>Array arr, <TYPE>* array, jint mode);用這個(gè)函數(shù)可以選擇將如何處理javac++的數(shù)組。是提交,還是撤銷等,內(nèi)存釋放還是不釋放。mode可以去下面的值:0(對(duì)java的數(shù)組進(jìn)行更新并釋放c/c++的數(shù)組)

JNI_COMMIT(對(duì)java的數(shù)組進(jìn)行更新但不釋放c/c++的數(shù)組

JNI_ABORT (對(duì)java的數(shù)組不進(jìn)行更新,釋放c/c++的數(shù)組)

.GetPrimitiveArrayCritical(jarray arr, jboolean* isCopied);

 ReleasePrimitiveArrayCritical(jarray arr, void* array, jint mode);它們也是jdk1.2出來的,為了增加直接傳回指向java數(shù)組的指針而加入的函數(shù)。同樣的,也會(huì)有同GetStringCritical的死鎖的問題。

.Get<TYPE>ArrayRegion(<TYPE>Array arr, jsize start, jsize len,<TYPE>* buffer);c/c++預(yù)先開辟一段內(nèi)存,然后把java基本類型的數(shù)組拷貝到這段內(nèi)存中。跟GetStringRegion原理類似。

.Set<TYPE>ArrayRegion(<TYPE>Array arr, jsize start, jsize len, const<TYPE>* buffer);java基本類型的數(shù)組中的指定范圍的元素用c/c++的數(shù)組中的元素來賦值。

.<TYPE>Array New<TYPE>Array(jsize size);指定一個(gè)長度然后返回相應(yīng)的java基本類型的數(shù)組。

 

處理對(duì)象類型的數(shù)組【Object[]

JNI沒有提供直接把java的對(duì)象類型數(shù)組(Object[])直接轉(zhuǎn)到c/c++中的jobject[]數(shù)組的函數(shù);而是直接通過GetObjectArrayElement (JNIEnv *env, jobjectArray arrayjsize index)/ SetObjectArrayElement (JNIEnv *env, jobjectArray arrayjsize index, jobject val)這樣的函數(shù)來對(duì)javaObject[]數(shù)組進(jìn)行操作。

.使用上述的函數(shù)也不用釋放任何資源。

.NewObjectArray(jsize lenjclass clazzjobject init)可以通過指定長度跟初始值來創(chuàng)建某個(gè)類的數(shù)組。

int[] arrays = {1,2,3,4,5,6,7,8,9,0};

public native void callCppFunction();

public static void main(String[] args) {

MainTest obj = new MainTest();

obj.callCppFunction();//這里會(huì)去訪問數(shù)組。

for(int each: obj.arrays) {

System.out.println(each);

}

}

全局引用/局部引用/弱全局引用

.java虛擬機(jī)創(chuàng)建的對(duì)象傳到本地c/c++代碼時(shí)會(huì)產(chǎn)生引用。根據(jù)java的垃圾回收機(jī)制,只要引用存在就不會(huì)觸發(fā)該引用指向的java對(duì)象的垃圾回收。

.這些引用在JNI中分為三種:

局部引用(Local Reference);最常見的引用類型。基本上通過JNI返回來的引用都是局部引用。

例如使用NewObject就會(huì)返回創(chuàng)建出來的實(shí)例的局部引用。局部引用只在該Native函數(shù)中有效。所有在該函數(shù)中產(chǎn)生的局部引用,都會(huì)在函數(shù)返回的時(shí)候自動(dòng)釋放。也可以使用deleteLocalRef函數(shù)手動(dòng)釋放該引用。

注意:既然局部引用能夠在函數(shù)返回時(shí)自動(dòng)釋放,為什么還需要deleteRef()函數(shù)呢?

實(shí)際上局部引用存在,就會(huì)防止其指向的對(duì)象被垃圾回收。尤其是當(dāng)一個(gè)局部引用指向一個(gè)龐大的對(duì)象,或是在一個(gè)循環(huán)中生成了局部引用,最好的做法就是在使用完該對(duì)象后,或在該循環(huán)尾部把這個(gè)引用釋放掉,以確保在垃圾回收器被觸發(fā)的時(shí)候被回收。

在局部引用的有效期中,可以傳遞到別的本地函數(shù)中,要強(qiáng)調(diào)的是它的有效期仍然只在一次的java本地函數(shù)調(diào)用中,所以千萬不能用c++全局變量保存它或是把它定義為c++靜態(tài)局部變量。

全局引用(Global Reference);

全局引用可以跨越當(dāng)前線程,在多個(gè)native函數(shù)中有效,不過需要編程人員手動(dòng)來釋放該引用。全局引用存在期間會(huì)防止在java的垃圾回收器中回收。

與局部引用不同的是,全局引用過的創(chuàng)建不是由JNI自動(dòng)創(chuàng)建的,全局引用是需要調(diào)用NewGlobalRef函數(shù),而釋放它需要使用ReleaseGlobalRef函數(shù)。

弱全局引用(Weak Global Reference);

其是jdk1.2出來的功能,與全局引用相似,創(chuàng)建跟刪除都需要編程人員手動(dòng)來進(jìn)行。這種引用與全局引用一樣可以在多個(gè)本地代碼有效,也跨越多線程有效。不一樣的是,這種夾棍不會(huì)阻止垃圾回收器回收這個(gè)引用所指向的對(duì)象。

使用NewWeakGlobalRefReleaseGlobalRef來產(chǎn)生和接觸引用。

關(guān)于的一些函數(shù):jobject NewGlobalRefjobject obj;

   Jobject NewLocalRef(jobject obj);

   Jobject NewWeakGlobalRef(jobject obj);

   Void  DeleteGlobalRef(jobject obj);

Void  DeleteLocalRef(jobject obj);

Void  DeleteWeakGlobalRef(jobject obj);

Jboolean IsSameObject(jobject obj1, jobject obj2);這個(gè)函數(shù)對(duì)于弱全局引用還有一個(gè)特別的功能:把null傳入要比較的對(duì)象中,就能夠判斷弱全局引用所指向的java對(duì)象是否被回收?!?/span>java native interface

緩存JfieldID/jmethodID

 .取得jfieldIDjmethodID的時(shí)候會(huì)通過該屬性/方法名稱上簽名來查詢相應(yīng)的jfieldID/jmethodID.這種查詢相對(duì)來說開銷較大。其實(shí),可以將這些FieldID/MethodID緩存起來,這樣只需查詢一次,以后就是使用緩存起來的FieldID/MethodID了。

介紹兩種緩存方式的實(shí)現(xiàn):

1、 在用的時(shí)候緩存:

.native code中使用static局部變量來保存已經(jīng)查詢過的id,這樣就不會(huì)在每次的函數(shù)調(diào)用是查詢,而只要第一次查詢成功后就保存起來了。

.不過在這種情況下不得不考慮多線程同時(shí)呼叫此函數(shù)時(shí)可能會(huì)造成同時(shí)查詢的情況。不過這種情況下沒必要擔(dān)心,所以是無害即是線程安全的。因?yàn)榉祷赝粋€(gè)ID

    Static fieldID fieldID_string = null;

Jclass clazz = env->GetObjectClass(obj);

If(fieldID_string == null)

{fieldID_string = envo->GetFieldID(clazz, stringLjava/lang/String;);

2、 java類初始化是緩存

.更好的方法就是在任何native函數(shù)調(diào)用錢把id全部存起來。

.可以在第一次加載這個(gè)類的時(shí)候首先調(diào)用本地代碼初始化所有的jfieldID/jmethodID,這樣的話就可以省去多次得確定ID是否存在的語句,當(dāng)然,這些jfieldID/jmethodID是定義在c/c++的全局。

.當(dāng)java類卸載或重新加載的時(shí)候也會(huì)重新呼叫給本地代碼來重新計(jì)算緩存的ID集。

(篇二完,后期篇是關(guān)于JNI異常處理/多線程/c/c++如何啟動(dòng)jvm(上面都沒有涉及,在后期博客會(huì)更新,因?yàn)榭从⑽牡臅g和理解又慢點(diǎn)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多