JNI 函数(五)数组操作
(一)、获取数组的长度
函数原型:jsize GetArrayLength(JNIEnv *env, jarray array)
返回数组的长度
参数:
env:JNI 接口指针
array:Java 数组
返回:
数组的长度
(二)、创建对象数组
函数原型:jobjectArray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);
创建一个新的对象数组,它的元素的类型是 elementClass,并且所有元素的默认值是 initialElement。
参数:
env:JNI 接口指针
length:数组大小
elementClass:数组元素类
initialElement:数组元素的初始值
返回:
Java 数组对象,如果无法构造数组,则返回 NULL
异常:
如果内存不足,则抛出 OutOfMemoryError
(三)、获取数组元中的某个元素
函数原型:jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);
返回元素中某个位置的元素
参数:
env:JNI 接口指针
array:Java 数组
index:数组下标
返回:
Java 对象
异常:
如果index下标不是一个有效的下标,则会抛出 ArrayIndexOutOfBoundsException
(四)、设置数组中某个元素的值
函数原型:void SetObjectArrayElement(JNIEnv *env,jobjectArray array,jsize index,jobject value);
设置下标为 index 元素的值。
参数:
env:JNI 接口指针
array:Java 数组
index:数组下标
value:数组元素的新值
异常:
如果 index 不是有效下标,则会抛出 ArrayIndexOutOfBoundsException
如果 value 不是元素类的子类,则会抛出 ArrayStoreException
(五)、创建基本类型数组系列
通用函数类型:ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);
用于构造基本类型数组对象的一系列操作。下面说明了特定基本类型数组的创建函数。可以把 New<PrimitiveType>Array 替换为某个实际的基本类型数组创建函数 ,然后将 ArrayType 替换为相应的数组类型
New<PrimitiveType>Array Routines | Array Type |
NewBooleanArray() | jbooleanArray |
NewByteArray() | jbyteArray |
NewCharArray() | jcharArray |
NewShortArray() | jshortArray |
NewIntArray() | jintArray |
NewLongArray() | jlongArray |
NewFloatArray() | jfloatArray |
NewDoubleArray() | jdoubleArray |
参数:
env:JNI 接口指针
length:数组长度
返回:
Java 数组,如果无法创建该数组,则返回 NULL。
(六)、获取基本类型数组的中数组指针系列
通用函数类型:NativeType * Get<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, jboolean * isCopy);
一组返回类型是基本类型的数组指针。在调用相应的 Release<PrimitiveType>ArrayElements() 函数前将一直有效。由于返回的数组可能是 Java 数组的副本,因此,对返回数组的变更没有在基本类型中反应出来。除非了调用了一组返回基本类型数组体的函数。结果在调用相应的 Release<PrimitiveType>ArrayElements() 函数前将一直有效。由于返回的数组可能是 Java 数组的副本,因此对返回数组的更改不必在基本类型数组中反映出来,直到调用 “ Release<PrimitiveType>ArrayElements() ” 函数。
如果 isCopy 不是 NULL,*isCopy 在复制完成后即被设为 JNI_TRUE 。如果未复制,则设为 JNI_FALSE。
下面说明了特定的基本类型数组元素的具体函数:
- 将 Get<PrimitiveType>ArrayElements 替换为表中某个实际的基本> 类型的函数
- 将 ArrayType 替换为对应的数组类型
- 将 NativeType 替换为本地变量
不管布尔数组在 Java 虚拟机总如何表示,GetBooleanArrayElements() 将始终返回一个 jboolean 类型的指针,其中每一个字节代表一个元素(开包表示)。内存中将确保所有其他类型的数组为连续的。
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 |
参数:
env:JNI 接口指针
array:Java 数组
isCopy:指向布尔值的指针
返回:
返回指向数组元素的指针,如果操作失败,则返回 NULL
(七)、释放基本类型的数组系列
通用函数原型:void Release<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, NativeType *elems, jint mode);
通知虚拟机 Native 不再访问数组的元素了。elems 参数是使用相应的 Get <PrimitiveType> ArrayElements() 函数数组返回的指针。如果有需要的话,该函数复制复制所有的 elems 上的变换到原始数组元素上去。mode 参数提供了数组 buffer 应该怎么被释放。如果elems 不是 array 的一个副本,mode 并没有什么影响。
mode 的取值 有如下 3 种情况:
- 0:复制内容并释放 elems 缓冲区
- JNI_COMMIT:复制内容但不释放 elems 缓冲区
- JNI_ABORT:释放缓冲区而不复制可能的更改
大多数情况下,程序员将 “0” 作为参数传递,因为这样可以确保固定和复制数组的一致行为。其他选项可以让程序员更好的控制内存。
下面说明了特定的基本类型数组元素的具体函数:
- 将 Release <PrimitiveType> ArrayElements 替换下面中某个实际的基本> 类型的函数
- 将 ArrayType 替换为对应的基本数组类型
- 将 NativeType 替换为本地变量
下面描述了基本类型数组释放的详情。 您应该进行以下替换:
Release<PrimitiveType>ArrayElements Routines | Array Type | Native Type |
ReleaseBooleanArrayElements() | jbooleanArray | jboolean |
ReleaseByteArrayElements() | jbyteArray | jbyte |
ReleaseCharArrayElements() | jcharArray | jchar |
ReleaseShortArrayElements() | jshortArray | jshort |
ReleaseIntArrayElements() | jintArray | jint |
ReleaseLongArrayElements() | jlongArray | jlong |
ReleaseFloatArrayElements() | jfloatArray | jfloat |
ReleaseDoubleArrayElements() | jdoubleArray | jdouble |
参数:
env:JNI 接口指针
array:Java 数组
elems:指向基本类型的数组的指针
mode:释放模式
(8)、将基本类型数组某一区域复制到缓冲区中
函数原型:Get<PrimitiveType> ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, NativeType *buf);
复制基本类型的数组给 buff
下面说明了特定的基本类型数组元素的具体函数:
- 将 Get<PrimitiveType> ArrayRegion 替换下面中某个实际的基本> 类型的函数
- 将 ArrayType 替换为对应的基本数组类型
- 将 NativeType 替换为本地变量
Get<PrimitiveType>ArrayRegion Routine | Array Type | Native Type |
GetBooleanArrayRegion() | jbooleanArray | jboolean |
GetByteArrayRegion() | jbyteArray | jbyte |
GetCharArrayRegion() | jcharArray | jchar |
GetShortArrayRegion() | jshortArray | jshort |
GetIntArrayRegion() | jintArray | jint |
GetLongArrayRegion() | jlongArray | jlong |
GetFloatArrayRegion() | jfloatArray | jfloat |
GetDoubleArrayRegion() | jdoubleArray | jdouble |
参数:
env:JNI 接口指针
array:Java 数组
start:开始索引
len:需要复制的长度
buf:目标 buffer
异常:
如果索引无效,则抛出 ArrayIndexOutOfBoundsException
(九)、基本类型数组的某一区域从缓冲区中复制回来
函数原型:void Set<PrimitiveType> ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, const NativeType *buf);
主要是冲缓冲区复制基本类型的数组的函数
下面说明了特定的基本类型数组元素的具体函数:
- 将 Set<PrimitiveType>ArrayRegion 替换下面中某个实际的基本> 类型的函数
- 将 ArrayType 替换为对应的基本数组类型
- 将 NativeType 替换为本地变量
Set<PrimitiveType>ArrayRegion Routine | Array Type | Native Type |
SetBooleanArrayRegion() | jbooleanArray | jboolean |
SetByteArrayRegion() | jbyteArray | jbyte |
SetCharArrayRegion() | jcharArray | jchar |
SetShortArrayRegion() | jshortArray | jshort |
SetIntArrayRegion() | jintArray | jint |
SetLongArrayRegion() | jlongArray | jlong |
SetFloatArrayRegion() | jfloatArray | jfloat |
SetDoubleArrayRegion() | jdoubleArray | jdouble |
参数:
env:JNI 接口指针
array:Java 数组
start:开始索引
len:需要复制的长度
buf:源 buffer
异常:
如果索引无效则会抛出 ArrayIndexOutOfBoundsException
(十)、补充
从 JDK/JER 1.1 开始提供 Get/Release<primitivetype>ArrayElements 函数获取指向原始数组元素的指针。如果 VM 支持锁定,则返回指向原始数组的指针,否则,复制。
从 JDK/JRE 1.3 开始引入新的功能即便 VM 不支持锁定,本地代码也可以获取数组元素的直接指针,
函数原型:void *GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy);
函数原型:void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode);
虽然这两个函数与上面的 Get/Release <primitivetype> ArrayElements 函数很像,但是在使用这个功能的时候,还是有很多的限制。
在调用 GetPrimitiveArrayCritical 之后,调用 ReleasePrimitiveArrayCritical 之前,这个区域是不能调用其他 JNI 函数,而且也不能调用任何可能导致线程阻塞并等待另一个 Java 线程的系统调用。
比如,当前线程不能调用 read 函数来读取,正在被其他所写入的 stream。