- 基本类型
- 字符串
- 数组
#1. 基本类型
Java语言中数据类型分为基本数据类型和引用数据类型,其中基本数据类型分为四类八种:整型:byte,short,int,long; 浮点型:float,double; 布尔型:bool; 字符型:char。
JNI层也提供了与基本类型对应的八种数据类型:jboolean,jbyte,jchar,jshort,jint,jlong,jfloat和jdouble。
/* Primitive types that match up with Java equivalents. */
typedef uint8_t jboolean; /* unsigned 8 bits */
typedef int8_t jbyte; /* signed 8 bits */
typedef uint16_t jchar; /* unsigned 16 bits */
typedef int16_t jshort; /* signed 16 bits */
typedef int32_t jint; /* signed 32 bits */
typedef int64_t jlong; /* signed 64 bits */
typedef float jfloat; /* 32-bit IEEE 754 */
typedef double jdouble; /* 64-bit IEEE 754 */
对应的映射关系为:
Java | Native类型 | 符号属性 | 字长 |
---|---|---|---|
boolean | jboolean | 无符号 | 8位 |
byte | jbyte | 有符号 | 8位 |
char | jchar | 无符号 | 16位 |
short | jshort | 有符号 | 16位 |
int | jint | 有符号 | 32位 |
long | jlong | 有符号 | 64位 |
float | jfloat | 有符号 | 32位 |
double | jdouble | 有符号 | 64位 |
#2. 字符串
Java中String表示字符串,在JNI数据类型中jstring与之对应。jstring本身是一个指针,指向的是Java virtual machine里面的一个字符串。jstring所代表的字符串与传统的c string不同,但是可以通过JNI函数将jstring转换为c string。
class _jstring : public _jobject {};
typedef _jstring* jstring;
#2.1 获得字符串
JNI中提供了一系列进行jstring和c string相互转换的函数。
GetStringChars
将jstring转换为Unicode编码的c string,并返回指向字符串的指针。指针会一直有效,除非调用ReleaseStringchars。
const jchar * GetStringChars(JNIEnv *env, jstring string,jboolean *isCopy);
ReleaseStringChars
通知vm释放GetStringChars所获得的字符串。参数chars正是GetStringChars所返回的指针。
void ReleaseStringChars(JNIEnv *env, jstring string,const jchar *chars);
GetStringUTFChars
将jstring转换为UTF-8编码的c string,并返回指向字符串的指针。指针会一直有效,除非调用ReleaseStringUTFChars。
const char * GetStringUTFChars(JNIEnv *env, jstring string,jboolean *isCopy);
/*
* Convert "string" to modified UTF-8 and return a pointer. The returned
* value must be released with ReleaseStringUTFChars.
*
* According to the JNI reference, "Returns a pointer to a UTF-8 string,
* or NULL if the operation fails. Returns NULL if and only if an invocation
* of this function has thrown an exception."
*
* The behavior here currently follows that of other open-source VMs, which
* quietly return NULL if "string" is NULL. We should consider throwing an
* NPE. (The CheckJNI code blows up if you try to pass in a NULL string,
* which should catch this sort of thing during development.) Certain other
* VMs will crash with a segmentation fault.
*/
static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
ScopedJniThreadState ts(env);
if (jstr == NULL) {
/* this shouldn't happen; throw NPE? */
return NULL;
}
if (isCopy != NULL) {
*isCopy = JNI_TRUE;
}
StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
char* newStr = dvmCreateCstrFromString(strObj);
if (newStr == NULL) {
/* assume memory failure */
dvmThrowOutOfMemoryError("native heap string alloc failed");
}
return newStr;
}
ReleaseStringUTFChars
通知vm释放GetStringUTFChars所获得的字符串。参数utf正是GetStringUTFChars所返回的指针。
void ReleaseStringUTFChars(JNIEnv *env, jstring string,const char *utf);
/*
* Release a string created by GetStringUTFChars().
*/
static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) {
ScopedJniThreadState ts(env);
free((char*) utf);
}
NewString
将Unicode编码的c string转换为jstring。
jstring NewString(JNIEnv *env, const jchar *unicodeChars,jsize len);
NewStringUTF
将UTF-8编码的c string转换为jstring。(vm中string是unicode编码,同时新string产生在vm中,属于托管内存,由GC负责回收。)
jstring NewStringUTF(JNIEnv *env, const char *bytes);
GetStringUTFLength
获取UTF-8编码字符串的长度。
jsize GetStringUTFLength(JNIEnv *env, jstring string);
#3. 数组
根据JNI层处理数组方式的不同,我们将数组也分为基础类型数组和引用类型数组。基础类型的数组如:int[]、float[];引用类型的数组如:Object[]。
int[] iarr;
float[] farr;
Object[] oarr;
int[][] arr2;
iarr和farr为基础类型的数组,oarr和arr2为引用类型的数组。
3.1 基础类型数组
JNI层提供了一系列的函数来操作基础类型的数组,Get/Release<Type>ArrayElements。
3.1.1 Get<PrimitiveType>ArrayElements Routines
Get系列的函数簇用来处理Java层的基础类型的数组。返回的指针一直有效除非手动调用
Release<PrimitiveType>ArrayElements进行释放。
NativeType *Get<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array, jboolean *isCopy);
Get<PrimitiveType>ArrayElements Routines | Array Type | Native Type |
---|---|---|
GetBooleanArrayElements() | jbooleanArray | jboolean |
GetByteArrayElements() | jbyteArray | jbyte |
GetCharArrayElements() | jcharArray | jchar |
GetShortArrayElements() | jshortArray | jshort |
GetIntArrayElements() | jintArray | jint |
GetLongArrayElements() | jlongArray | jlong |
GetFloatArrayElements() | jfloatArray | jfloat |
GetDoubleArrayElements() | jdoubleArray | jdouble |
3.1.2 Release<PrimitiveType>ArrayElements Routines
Release系列的函数集用来通知vm Get所产生的数组不再需要。
void Release<PrimitiveType>ArrayElements(JNIEnv*env,ArrayType array,
NativeType *elems, jint mode);
mode参数用来表示数组如何被释放,如果Get系列函数产生的数组非拷贝生成,mode无效;否则根据mode类型不同,产生不同的释放效果。
mode | actions |
---|---|
0 | copy back the content and free the elems buffer |
JNI_COMMIT | copy back the content but do not free the elems buffer |
JNI_ABORT | free the buffer without copying back the possible changes |
3.1.3 New<PrimitiveType>Array Routines
New系列的函数集用来创建基础类型的Java数组。
ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);
New<PrimitiveType>Array Routines | Array Type |
---|---|
NewBooleanArray() | jbooleanArray |
NewByteArray() | jbyteArray |
NewCharArray() | jcharArray |
NewShortArray() | jshortArray |
NewIntArray() | jintArray |
NewLongArray() | jlongArray |
NewFloatArray() | jfloatArray |
NewDoubleArray() | jdoubleArray |
3.1.4 示例
JNIEXPORT jint JNICALL Java_com_nextlabs_hhu_myapplication_core_JNIHandler_sumArray
(JNIEnv *env, jclass clazz, jintArray arr) {
jsize len = env->GetArrayLength(arr);
jint *carr = env->GetIntArrayElements(arr, nullptr);
if (carr == nullptr) {
return 0;
}
jint sum = 0;
for (int i = 0; i < len; ++i) {
sum += carr[i];
}
return sum;
}
3.2 引用类型数组
3.2.1 GetObjectArrayElement
GetObjectArrayElement返回指定index处的元素。
jobject GetObjectArrayElement(JNIEnv *env,jobjectArray array, jsize index);
3.2.2 SetObjectArrayElement
SetObjectArrayElement更新指定index处的元素。
void SetObjectArrayElement(JNIEnv *env, jobjectArray array,jsize index, jobject value);
3.2.3 NewObjectArray
NewObjectArray根据elementClass的类型创建Object数组,数组元素的初始值为initialElement。
jobjectArray NewObjectArray(JNIEnv *env, jsize length,jclass elementClass, jobject initialElement);
3.2.4 示例
JNIEXPORT jobjectArray JNICALL Java_com_nextlabs_hhu_myapplication_core_JNIHandler_initInt2DArray
(JNIEnv *env, jclass clazz, jint size) {
jobjectArray rt;
jclass intArrClass = env->FindClass("[I");
if (intArrClass == nullptr) {
return nullptr;
}
rt = env->NewObjectArray(size, intArrClass, nullptr);
if (rt == nullptr) {
return nullptr;
}
//Fill object array.
for (int i = 0; i < size; i++) {
jint buf[256];
jintArray elem = env->NewIntArray(size);
if (elem == nullptr) {
continue;
}
for (int j = 0; j < size; j++) {
buf[j] = i + j;
}
env->SetIntArrayRegion(elem, 0, size, buf);
env->SetObjectArrayElement(rt, i, elem);
env->DeleteLocalRef(elem);
}
return rt;
}