Java Native Interface 二 JNI中对Java基本类型和引用类型的处理
本文是《The Java Native Interface Programmer’s Guide and Specification》讀書筆記
Java編程里會使用到兩種類型:基本類型(如int,float等)和引用類型(如class,instance,arrays),JNI編程里對這兩種的類型的處理方法也是不一樣的。
JNI定義了與Java的基本類型和引用類型相對應(yīng)的C/C++類型:
| boolean | jboolean |
| int | jint |
| float | jfloat |
| byte | jbyte |
| char | jchar |
| short | jshort |
| long | jlong |
| double | jdouble |
Java中所有對象都是Object類的子類,在JNI中與之對應(yīng)的為jobject類,所有的類型都是jobject類的子類,直接繼承自jobject 的引用類型:
| java.lang.Class | jclass |
| java.lang.String | jstring |
| arrays | jarray |
| java.lang.Throwable | jthrowable |
其中數(shù)組又會有其他的子類型,如Java中的int[] 對應(yīng)到JNI中為jintArray,Object[]對應(yīng)為jobjectArray[]等;
在使用C++時,類的繼承的語法為
class _jobjct{}; class _jclass:public_jobjct{};//公有繼承同時在JNI中會使用類標(biāo)識符來表示Java中的類或接口。數(shù)組用'['來標(biāo)識,如int[]在JNI中用'[I'來標(biāo)識,三維數(shù)組double[][][],用['[[[D'來標(biāo)識;下面是JNI中常用基本類型的標(biāo)識符與對應(yīng)的Java類:
| Z | boolean |
| B | byte |
| C | char |
| S | short |
| I | int |
| J | long |
| F | float |
| D | double |
JNI中引用類型的標(biāo)識符以字符'L'開始,并以';'結(jié)束,但數(shù)組的標(biāo)識符與前面的基本類型的標(biāo)識符相同;
| "Ljava/lang/String;" | String |
| "[I" | int[] |
| "[Ljava/lang/Object;" | Object[] |
在JNI中方法的標(biāo)識符里,方法所含的參數(shù)之間是沒有空格隔開的,并用字符"V"作為void方法的返回標(biāo)識;構(gòu)造函數(shù)一般使用"V"作為返回值,"init"作為名字;
| "()Ljava/lang/String; " | String f() |
| "(ILjava/lang/Class;)J" | long f(int i,Class c) |
| "([B)V" | String(byte[]bytes) |
在了解完JNI中對應(yīng)的類型與標(biāo)識符后,接下來就是怎樣使用它們了。
String類型的使用
在實現(xiàn)本地方法時,必須使用JNI的方法將對應(yīng)的jstring對象類型轉(zhuǎn)型為c/c++可以識別的string 對象,否則在調(diào)用這個本地方法時會導(dǎo)致Java虛擬機崩潰;
假設(shè)有一個本地方法,在Java里聲明為:
則你在實現(xiàn)這個方法時,不能這樣寫:
JNIEXPORT jstring JNICALL Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt) {/* ERROR: incorrect use of jstring as a char* pointer */printf("%s", prompt);... }你可以這樣寫:
JNIEXPORT jstring JNICALL Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt) {char buf[128];const jbyte *str;str = (*env)->GetStringUTFChars(env, prompt, NULL);//必須要記得檢查JNI方法的返回值,因為JVM在執(zhí)行時需要分配內(nèi)存,可能存在內(nèi)存分配失敗的情況if (str == NULL) {return NULL; /* OutOfMemoryError already thrown */}printf("%s", str);//當(dāng)使用完JNI方法返回的對象后,調(diào)用相應(yīng)的Release方法釋放掉對應(yīng)的內(nèi) 存,忘記使用Release方法可能會導(dǎo)致內(nèi)存泄漏(*env)->ReleaseStringUTFChars(env, prompt, str);/* We assume here that the user does not type more than* 127 characters */scanf("%s", buf);return (*env)->NewStringUTF(env, buf); }jni中的可以對String(jstring)對象使用的方法總結(jié):
| GetStringChars,ReleaseStringChars | 獲取或釋放一個指向Unicode編碼的字符串內(nèi)容的指針,可能會返回一個字符串的拷貝 |
| GetStringUTFChars,ReleaseStringUTFChars | 獲取或釋放一個指向UTF-8編碼的字符串內(nèi)容的指針,可能會返回一個字符串的拷貝 |
| GetStrinLength | 返回字符串里Unicode編碼的字符的個數(shù) |
| GetStringUTFLength | 返回字符串里UTF-8編碼的字符的個數(shù) |
| NewString | 創(chuàng)建一個包含給定的Unicode編碼的C字符串的所有字符的java.lang.String實例 |
| NewStringUTF | 創(chuàng)建一個包含給定的UTF-8編碼的C字符串的所有字符的java.lang.String實例 |
| GetStringCritical,ReleaseStringCritical | 獲取一個指向Unicode編碼的字符串內(nèi)容的指針,可能返回一個字符串的拷貝。并且本地代碼在調(diào)用Get/ReleaseStrinCritical這對方法時,不能阻塞。 |
| GetStringUTFRegion,SetStringUTFRegion | 從一個預(yù)先分配的UTF-8格式的C的緩沖區(qū)拷貝字符串內(nèi)容(或?qū)⒆址畠?nèi)容寫入緩沖區(qū)中) |
Arrays類型的使用
JNI對普通數(shù)組(基本類型的數(shù)組,如int[],float[])和對象數(shù)組的處理方法是不一樣的。下面以簡單的例子來說明:
1 普通的數(shù)組的使用
求一個數(shù)組的和的例子:Java Class為:
class IntArray {private native int sumArray(int[] arr);//jni方法,求數(shù)組的和public static void main(String[] args) {IntArray p = new IntArray();int arr[] = new int[10];for (int i = 0; i < 10; i++) {arr[i] = i;}int sum = p.sumArray(arr);System.out.println("sum = " + sum);}static {System.loadLibrary("IntArray");} }Java的Arrays在JNI中用jarrays和它的子類,如jintArray來表示,就像jstring不是C字符串的類型,jarrays也不是C的數(shù)組類型,因此,你不能在實現(xiàn)JNI方法時,直接使用jarrays的引用,下面是錯誤的JNI方法的編寫:
JNIEXPORT jint JNICALL Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr) {int i, sum = 0;for (i = 0; i < 10; i++) {sum += arr[i];} }正確的JNI的方法應(yīng)該為:
JNIEXPORT jint JNICALL Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr) {jint buf[10];jint i, sum = 0;(*env)->GetIntArrayRegion(env, arr, 0, 10, buf);for (i = 0; i < 10; i++) {sum += buf[i];}return sum; }也可以這樣寫:
JNIEXPORT jint JNICALL Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr) {jint *carr;jint i, sum = 0;carr = (*env)->GetIntArrayElements(env, arr, NULL);if (carr == NULL) {return 0; /* exception occurred */}for (i=0; i<10; i++) {sum += carr[i];}(*env)->ReleaseIntArrayElements(env, arr, carr, 0);return sum; }JNI中可以對基本類型數(shù)組使用的方法有:
:表示需要用基本類型來替代,如GetArrayRegion,就可以有GetIntArrayRegion,GetFloatArrayRegion等;
| GetArrayRegion,SetArrayRegion | 得到基本類型的數(shù)組的內(nèi)容,或?qū)?nèi)容寫入預(yù)先分配的C的緩沖區(qū)里 |
| GetArrayElements,ReleaseArrayElements | 獲得一個指向基本類型數(shù)組的內(nèi)容的指針,可能會返回一個數(shù)組的拷貝 |
| GetArrayLength | 返回數(shù)組的大小 |
| NewArray | 創(chuàng)建一個給定長度的數(shù)組 |
| GetPrimitiveArrayCritical,ReleasePrimitiveArrayCritical | 獲得或釋放指向基本類型數(shù)組的內(nèi)容的指針 |
2 對象數(shù)組的使用:
JNI提供了許多對方法來得到對象數(shù)組。GetObjectElement方法會返回一個給定位置的元素,SetObjectElement方法更新給定位置的元素。但我們不能一次性就得到(復(fù)制)所有的對象數(shù)組里的元素。下面還是以簡單的例子來說明:
Java Class為:
本地方法的實現(xiàn)為:
JNIEXPORT jobjectArray JNICALL Java_ObjectArrayTest_initInt2DArray(JNIEnv *env,jclass cls,int size) {jobjectArray result;int i;//獲得一個元素類型(Int)的Class引用,類似于Java中得到某一類型的類加載器jclass intArrCls = (*env)->FindClass(env, "[I");if (intArrCls == NULL) {return NULL; /* exception thrown */}//生成一個元素類型為intArrCls的數(shù)組,這個方法只能生成一維數(shù)組result = (*env)->NewObjectArray(env, size, intArrCls, NULL);if (result == NULL) {return NULL; /* out of memory error thrown */}for (i = 0; i < size; i++) {jint tmp[256]; /* make sure it is large enough! */int j;//生成數(shù)組里存放的元素(仍然為一個數(shù)組)jintArray iarr = (*env)->NewIntArray(env, size);if (iarr == NULL) {return NULL; /* out of memory error thrown */}for (j = 0; j < size; j++) {tmp[j] = i + j;}//用tmp里的元素填充iarr數(shù)組,使用的是基本類型數(shù)組的方法(*env)->SetIntArrayRegion(env, iarr, 0, size, tmp);//將iarr作為數(shù)組元素填充到result數(shù)組相應(yīng)位置中,使用的是對象數(shù) 組的方法(*env)->SetObjectArrayElement(env, result, i, iarr);//釋放到對iarr對象的引用(*env)->DeleteLocalRef(env, iarr);}//二維數(shù)組就是數(shù)組里存放的元素仍然為數(shù)組,返回一個對象數(shù)組return result; }轉(zhuǎn)載于:https://www.cnblogs.com/WoodJim/p/4794772.html
總結(jié)
以上是生活随笔為你收集整理的Java Native Interface 二 JNI中对Java基本类型和引用类型的处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [部署]CentOS安装PHP环境
- 下一篇: UI:UITableView表视图