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

首頁(yè) > 系統(tǒng) > Android > 正文

Android中的JNI數(shù)組操作教程

2019-12-12 00:44:06
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

前言

JNI 中有兩種數(shù)組操作,基礎(chǔ)數(shù)據(jù)類型數(shù)組和對(duì)象數(shù)組,JNI 對(duì)待基礎(chǔ)數(shù)據(jù)類型數(shù)組和對(duì)象數(shù)組是不一樣的。

基本數(shù)據(jù)類型數(shù)組

對(duì)于基本數(shù)據(jù)類型數(shù)組,JNI 都有和 Java 相對(duì)應(yīng)的結(jié)構(gòu),在使用起來(lái)和基本數(shù)據(jù)類型的使用類似。

在 Android JNI 基礎(chǔ)知識(shí)篇提到了 Java 數(shù)組類型對(duì)應(yīng)的 JNI 數(shù)組類型。比如,Java int 數(shù)組對(duì)應(yīng)了 jintArray,boolean 數(shù)組對(duì)應(yīng)了 jbooleanArray。

如同 String 的操作一樣,JNI 提供了對(duì)應(yīng)的轉(zhuǎn)換函數(shù):GetArrayElements、ReleaseArrayElements。

 intArray = env->GetIntArrayElements(intArray_, NULL); env->ReleaseIntArrayElements(intArray_, intArray, 0);

另外,JNI 還提供了如下的函數(shù):

GetTypeArrayRegion / SetTypeArrayRegion

將數(shù)組內(nèi)容復(fù)制到 C 緩沖區(qū)內(nèi),或?qū)⒕彌_區(qū)內(nèi)的內(nèi)容復(fù)制到數(shù)組上。

GetArrayLength

得到數(shù)組中的元素個(gè)數(shù),也就是長(zhǎng)度。

NewTypeArray

返回一個(gè)指定數(shù)據(jù)類型的數(shù)組,并且通過(guò) SetTypeArrayRegion 來(lái)給指定類型數(shù)組賦值。

GetPrimitiveArrayCritical / ReleasePrimitiveArrayCritical

如同 String 中的操作一樣,返回一個(gè)指定基礎(chǔ)數(shù)據(jù)類型數(shù)組的直接指針,在這兩個(gè)操作之間不能做任何阻塞的操作。

實(shí)際操作如下:

 // Java 傳遞 數(shù)組 到 Native 進(jìn)行數(shù)組求和 private native int intArraySum(int[] intArray, int size);

對(duì)應(yīng)的 C++ 代碼如下:

JNIEXPORT jint JNICALLJava_com_glumes_cppso_jnioperations_ArrayTypeOps_intArraySum(JNIEnv *env, jobject instance,        jintArray intArray_, jint num) { jint *intArray; int sum = 0; // 操作方法一: // 如同 getUTFString 一樣,會(huì)申請(qǐng) native 內(nèi)存 intArray = env->GetIntArrayElements(intArray_, NULL); if (intArray == NULL) { return 0; } // 得到數(shù)組的長(zhǎng)度 int length = env->GetArrayLength(intArray_); LOGD("array length is %d", length); for (int i = 0; i < length; ++i) { sum += intArray[i]; } LOGD("sum is %d", sum); // 操作方法二: jint buf[num]; // 通過(guò) GetIntArrayRegion 方法來(lái)獲取數(shù)組內(nèi)容 env->GetIntArrayRegion(intArray_, 0, num, buf); sum = 0; for (int i = 0; i < num; ++i) { sum += buf[i]; } LOGD("sum is %d", sum); // 使用完了別忘了釋放內(nèi)存 env->ReleaseIntArrayElements(intArray_, intArray, 0); return sum;}

假如需要從 JNI 中返回一個(gè)基礎(chǔ)數(shù)據(jù)類型的數(shù)組,對(duì)應(yīng)的代碼如下:

 // 從 Native 返回基本數(shù)據(jù)類型數(shù)組 private native int[] getIntArray(int num);

對(duì)應(yīng)的 C++ 代碼如下:

/** * 從 Native 返回 int 數(shù)組,主要調(diào)用 set<Type>ArrayRegion 來(lái)填充數(shù)據(jù),其他數(shù)據(jù)類型類似操作 */extern "C"JNIEXPORT jintArray JNICALLJava_com_glumes_cppso_jnioperations_ArrayTypeOps_getIntArray(JNIEnv *env, jobject instance,        jint num) { jintArray intArray; intArray = env->NewIntArray(num); jint buf[num]; for (int i = 0; i < num; ++i) { buf[i] = i * 2; } // 使用 setIntArrayRegion 來(lái)賦值 env->SetIntArrayRegion(intArray, 0, num, buf); return intArray;}

以上例子,基本把相關(guān)的操作都使用上了,可以發(fā)現(xiàn)和 String 的操作大都是相似的。

對(duì)象數(shù)組

對(duì)于對(duì)象數(shù)組,也就是引用類型數(shù)組,數(shù)組中的每個(gè)類型都是引用類型,JNI 只提供了如下函數(shù)來(lái)操作。

GetObjectArrayElement / SetObjectArrayElement

和基本數(shù)據(jù)類型不同的是,不能一次得到數(shù)據(jù)中的所有對(duì)象元素或者一次復(fù)制多個(gè)對(duì)象元素到緩沖區(qū)。只能通過(guò)上面的函數(shù)來(lái)訪問(wèn)或者修改指定位置的元素內(nèi)容。

字符串和數(shù)組都是引用類型,因此也只能通過(guò)上面的方法來(lái)訪問(wèn)。

例如在 JNI 中創(chuàng)建一個(gè)二維的整型數(shù)組并返回:

 // 從 Native 返回二維整型數(shù)組,相當(dāng)于是一個(gè)一維整型數(shù)組,數(shù)組中的每一項(xiàng)內(nèi)容又是數(shù)組 private native int[][] getTwoDimensionalArray(int size);

二維數(shù)組具有特殊性在于,可以將它看成一維數(shù)組,其中數(shù)組的每項(xiàng)內(nèi)容又是一維數(shù)組。

具體 C++ 代碼如下:

/** * 從 Native 返回一個(gè)二維的整型數(shù)組 */extern "C"JNIEXPORT jobjectArray JNICALLJava_com_glumes_cppso_jnioperations_ArrayTypeOps_getTwoDimensionalArray(JNIEnv *env,         jobject instance,         jint size) { // 聲明一個(gè)對(duì)象數(shù)組 jobjectArray result; // 找到對(duì)象數(shù)組中具體的對(duì)象類型,[I 指的就是數(shù)組類型 jclass intArrayCls = env->FindClass("[I"); if (intArrayCls == NULL) { return NULL; } // 相當(dāng)于初始化一個(gè)對(duì)象數(shù)組,用指定的對(duì)象類型 result = env->NewObjectArray(size, intArrayCls, NULL); if (result == NULL) { return NULL; } for (int i = 0; i < size; ++i) { // 用來(lái)給整型數(shù)組填充數(shù)據(jù)的緩沖區(qū) jint tmp[256]; // 聲明一個(gè)整型數(shù)組 jintArray iarr = env->NewIntArray(size); if (iarr == NULL) {  return NULL; } for (int j = 0; j < size; ++j) {  tmp[j] = i + j; } // 給整型數(shù)組填充數(shù)據(jù) env->SetIntArrayRegion(iarr, 0, size, tmp); // 給對(duì)象數(shù)組指定位置填充數(shù)據(jù),這個(gè)數(shù)據(jù)就是一個(gè)一維整型數(shù)組 env->SetObjectArrayElement(result, i, iarr); // 釋放局部引用 env->DeleteLocalRef(iarr); } return result;}

首先需要使用 NewObjectArray 方法來(lái)創(chuàng)建對(duì)象數(shù)組。

然后使用 SetObjectArrayElement 函數(shù)填充數(shù)據(jù)時(shí),需要構(gòu)建好每個(gè)位置對(duì)應(yīng)的對(duì)象。這里就使用了 NewIntArray 來(lái)創(chuàng)造了一個(gè)對(duì)象,并給對(duì)象填充數(shù)據(jù)后,在賦值給對(duì)象數(shù)組。

通過(guò)一個(gè) for 循環(huán)就完成給對(duì)象數(shù)組賦值的操作。

在創(chuàng)建對(duì)象數(shù)組時(shí),有一個(gè)操作是找到對(duì)應(yīng)的對(duì)象類型,通過(guò) findClass 方法。findClass 的參數(shù) [I 這里就涉及到 Java 與 JNI 對(duì)應(yīng)簽名的轉(zhuǎn)換。

Java 與 JNI 簽名的轉(zhuǎn)換

在前一篇文章中,用表格列出了 Java 與 JNI 對(duì)應(yīng)的數(shù)據(jù)類型格式的轉(zhuǎn)換關(guān)系,現(xiàn)在要列舉的是 Java 與 JNI 對(duì)應(yīng)簽名的轉(zhuǎn)換關(guān)系。

這里的簽名指的是在 JNI 中去查找 Java 中對(duì)應(yīng)的數(shù)據(jù)類型、對(duì)應(yīng)的方法時(shí),需要將 Java 中的簽名轉(zhuǎn)換成 JNI 所能識(shí)別的。

對(duì)于類的簽名轉(zhuǎn)換

對(duì)于 Java 中類或者接口的轉(zhuǎn)換,需要用到 Java 中類或者接口的全限定名,把 Java 中描述類或者接口的 . 換成 / 就好了,比如 String 類型對(duì)應(yīng)的 JNI 描述為:

java/lang/String // . 換成 /

對(duì)于數(shù)組類型,則是用 [ 來(lái)表示數(shù)組,然后跟一個(gè)字段的簽名轉(zhuǎn)換。

[I   // 代表一維整型數(shù)組,I 表示整型[[I  // 代表二維整型數(shù)組[Ljava/lang/String;  // 代表一維字符串?dāng)?shù)組, 

對(duì)于字段的簽名轉(zhuǎn)換

對(duì)應(yīng)基礎(chǔ)類型字段的轉(zhuǎn)換:

Java 類型 JNI 對(duì)應(yīng)的描述轉(zhuǎn)
boolean Z
byte B
char C
short S
int I
long J
float F
double D

對(duì)于引用類型的字段簽名轉(zhuǎn)換,是大寫(xiě)字母 L 開(kāi)頭,然后是類的簽名轉(zhuǎn)換,最后以 ; 結(jié)尾。

Java 類型 JNI 對(duì)應(yīng)的描述轉(zhuǎn)換
String Ljava/lang/String;
Class Ljava/lang/Class;
Throwable Ljava/lang/Throwable
int[] "[I"
Object[] "[Ljava/lang/Object;"

對(duì)于方法的簽名轉(zhuǎn)換

對(duì)于方法簽名描述的轉(zhuǎn)換,首先是將方法內(nèi)所有參數(shù)轉(zhuǎn)換成對(duì)應(yīng)的字段描述,并全部寫(xiě)在小括號(hào)內(nèi),然后在小括號(hào)外再緊跟方法的返回值類型描述。

Java 類型 JNI 對(duì)應(yīng)的描述轉(zhuǎn)換
String f(); ()Ljava/lang/String;
long f(int i, Class c); (ILjava/lang/Class;)J
String(byte[] bytes); ([B)V

這里要注意的是在 JNI 對(duì)應(yīng)的描述轉(zhuǎn)換中不要出現(xiàn)空格。

了解并掌握這些轉(zhuǎn)換后,就可以進(jìn)行更多的操作了,實(shí)現(xiàn) Java 與 C++ 的相互調(diào)用。

比如,有一個(gè)自定義的 Java 類,然后再 Native 中打印類的對(duì)象數(shù)組的某一個(gè)字段值。

private native void printAnimalsName(Animal[] animal);

具體 C++ 代碼如下:

/** * 打印對(duì)象數(shù)組中的信息 */extern "C"JNIEXPORT void JNICALLJava_com_glumes_cppso_jnioperations_ArrayTypeOps_printAnimalsName(JNIEnv *env, jobject instance,                 jobjectArray animals) { jobject animal; // 數(shù)組長(zhǎng)度 int size = env->GetArrayLength(animals); // 數(shù)組中對(duì)應(yīng)的類 jclass cls = env->FindClass("com/glumes/cppso/model/Animal"); // 類對(duì)應(yīng)的字段描述 jfieldID fid = env->GetFieldID(cls, "name", "Ljava/lang/String;"); // 類的字段具體的值 jstring jstr; // 類字段具體值轉(zhuǎn)換成 C/C++ 字符串 const char *str; for (int i = 0; i < size; ++i) {  // 得到數(shù)組中的每一個(gè)元素  animal = env->GetObjectArrayElement(animals, i);  // 每一個(gè)元素具體字段的值  jstr = (jstring) (env->GetObjectField(animal, fid));  str = env->GetStringUTFChars(jstr, NULL);  if (str == NULL) {   continue;  }  LOGD("str is %s", str);  env->ReleaseStringUTFChars(jstr, str); }}

具體示例代碼可參考我的 Github 項(xiàng)目,歡迎 Star。

https://github.com/glumes/AndroidDevWithCpp (本地下載

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)武林網(wǎng)的支持。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 绥芬河市| 大竹县| 甘泉县| 石首市| 台湾省| 普安县| 合阳县| 陆河县| 油尖旺区| 博乐市| 盐池县| 昂仁县| 泊头市| 江门市| 荣成市| 聊城市| 静安区| 青田县| 阿拉善左旗| 仁布县| 瑞丽市| 井陉县| 浪卡子县| 桦甸市| 江安县| 西峡县| 台北县| 黎城县| 郑州市| 桂林市| 岑巩县| 南充市| 丰城市| 二手房| 黄平县| 弥渡县| 青海省| 阿拉善左旗| 美姑县| 平远县| 睢宁县|