JNI为访问对象数组单独提供了一组函数。GetObjectArrayElement返回指定下表的元素, 而SetObjectArrayElement则修改指定索引上的元素。与基础类型数组不同的是,你不能一次获取或者拷贝对象数组中的所有元素。
字符串和数组是引用类型,你需要使用Get/SetObjectArrayElement来访问字符串数组或者数组的数组。
以下示例代码通过调用原生代码创建了一个int型的二位数组,并打印出这个数组中的所有元素。
~~~
class ObjectArrayTest {
static {
System.loadLibrary("ObjectArrayTest");
}
private static native int[][] initInt2DArray(int size);
public static void main(String[] args) {
int[][] i2arr = initInt2DArray(3);
for (int i =0; i < 3; ++i) {
for (int j = 0; j < 3; j ++) {
System.out.print(" " + i2arr[i][j]);
}
System.out.println();
}
}
}
~~~
静态函数initInt2DArray根据给定长度创建了一个二维数组。原生函数负责开辟和初始化这个二维数组,实现如下:
~~~
/*
* Class: ObjectArrayTest
* Method: initInt2DArray
* Signature: (I)[[I
*/
JNIEXPORT jobjectArray JNICALL Java_ObjectArrayTest_initInt2DArray
(JNIEnv * env, jclass cls, jint size) {
jobjectArray result;
int i;
jclass intArrCls = (*env)->FindClass(env, "[I");
if(!intArrCls) {
return NULL; /* exception thrown */
}
result = (*env)->NewObjectArray(env, size, intArrCls, NULL);
if(!result) {
return NULL; /* out of memory error thrown */
}
for (i = 0; i < size; ++i) {
jint tmp[256]; /* make sure it is large enough! */
int j;
jintArray iarr = (*env)->NewIntArray(env, size);
if(!iarr) {
return NULL;
}
for (j = 0; j < size; j ++) {
tmp[j] = i + j;
}
(*env)->SetIntArrayRegion(env, iarr, 0, size, tmp);
(*env)->SetObjectArrayElement(env, result, i, iarr);
(*env)->DeleteLocalRef(env, iarr);
}
return result;
}
~~~
>请使用以下命令构建,路径需要修改:
>gcc -I/home/wangli/env/jdk8/usr/java/jdk1.8.0_20/include -I/home/wangli/env/jdk8/usr/java/jdk1.8.0_20/include/linux ObjectArrayTest.c -shared -o libObjectArrayTest.so -fPIC -std=c99
newInt2DArray函数首先调用FindClass获取一个二维int数组的类的引用。"[I"参数是int[]类型对应的JNI类描述符,我们会在12.3.2节讲解。如果累加载失败的话,FindClass会返回NULL并抛出异常(比如找不到类文件或者发生了out-of-memory错误)。
接下来使用NewObjectArray函数分配了一个数组,数组中的每一个元素的都是intArrCls对应的类型。NewObjectArray函数仅仅分配二维数组中的第一维,我们还需要填充二维数组的第二维。一个二维数组可以简单的理解为数组的数组。
用于创建二维数组的第二维的代码是非常直接的,NewIntArray分配独立的数组元素,SetIntArrayRegion则复制tmp[]缓冲区中的数据到全新构建的一维数组中去。在完成SetObjectArrayElement调用之后,第i个一维数组中的第j个元素的值是i+j.
运行ObjectArrayTest.main方法,将会产生如下输出:
~~~
0 1 2
1 2 3
2 3 4
~~~
循环最后的DeleteLocalRef函数调用是为了确保虚拟机不会因为需要持有大量像iarr这样的JNI引用而发生out-of-memory异常。在5.2.1章中我们会详细介绍为什么需要使用DeleteLocalRef以及应该在什么时候调用。
- JNI编程指南翻译
- 第一部分:介绍与入门
- 介绍
- Java平台与宿主环境
- JNI的角色
- 使用JNI的潜在风险
- 什么时候应该使用JNI
- JNI的进化
- 示例程序
- 入门
- 概览
- 声明一个Native方法
- 编译HelloWorld类
- 创建Native方法头文件
- 实现Native方法
- 编译C源码并创建一个Native库
- 执行程序
- 第二部分:编程指南
- 基础类型, Strings, Arrays
- 一个简单的Native方法
- Native方法实现的C语言原型
- Native方法的参数
- 类型映射
- 访问Strings
- 转换成为Native Strings
- 释放Native Strings资源
- 创建新的Strings
- String相关的其他JNI函数
- Java SDK2 中的新的String相关的JNI方法
- JNI String函数总结
- 在String函数中选择
- 访问Arrays
- 在C语言中操作数组
- 访问基础类型的数组
- JNI基础类型数组操作函数总结
- 如何在基础类型数组函数中做选择
- 访问对象数组
- 属性和方法
- 访问属性
- 如何访问一个对象实例的属性
- 属性描述符
- 访问静态属性
- 调用方法
- 调用对象实例方法
- 获取方法描述符
- 调用静态方法
- 调用对象的基类方法
- 调用构造函数
- 缓存属性和方法ID
- 在使用时缓存
- 在类初始化的时候缓存
- 两种ID缓存方式的对比
- JNI属性和方法操作的性能
- 局部和全局引用
- 局部和全局引用说明
- 局部引用
- 全局引用
- 弱全局引用
- 引用的比较
- 引用资源的释放
- 释放局部引用
- JDK2中的局部引用管理
- 释放全局引用
- 管理引用的原则
- 异常
- 概览
- 在Native代码中捕获与抛出异常
- 工具函数
- 异常处理最佳实践
- 异常检查
- 异常处理
- 工具函数中的异常
- The Invocation Interface
- 创建Java虚拟机
- 链接ava虚拟机到Native应用程序
- 链接某个确定的虚拟机实现
- 链接未知虚拟机
- 绑定Native线程
- 一些JNI特性
- JNI与线程
- 约束
- 监视进入与退出
- 监视等待和通知
- 如何从当前Context中获取JNIEnv的指针
- 匹配线程模型
- 编写国际化代码
- 注册Native方法
- 加载与卸载时机
- 加载时机
- 卸载时机
- 反射的支持
- 使用C++实现JNI
- 改变现有的Native库
- 一对一映射关系
- 共享桩
- 一对一映射VS共享桩
- 共享桩的实现
- Peer类
- Java平台中的Peer类
- 释放Native数据结构
- Peer类背后的指针
- 缺陷与陷阱
- 错误检查
- 向JNI函数传递非法参数
- jclass与jobject的困惑
- jboolean类型参数的截断机制
- Java应用与Native代码之间的边界
- ID与引用的困惑
- 缓存属性和方法ID
- 终结Unicode 字符串
- Violating访问控制原则
- 无视国际化
- 保持虚拟机资源
- 被滥用的局部引用创建
- 跨线程使用JNIEnv
- 错误使用的线程模型
- 第三部分:详细说明
- JNI设计概览
- 设计目标
- 加载Native库
- 类加载器
- 类加载器与Native库
- 加载Native库
- 类型安全限制
- 卸载Native库
- 链接Native方法
- 调用转换
- JNIEnv接口指针
- JNIEnv接口指针的组织
- 接口指针的好处
- 传递数据
- 全局和局部引用
- 局部引用的实现
- 弱全局引用
- 访问对象
- 访问原始数组
- 属性和方法
- 错误和异常
- 如果没有对编码错误的检查
- Java虚拟机异常
- 异步异常
- JNI类型
- 原始类型和引用类型
- 原始类型
- 引用类型
- jvalue类型
- 属性和方法ID
- 字符串格式
- UTF-8字符串
- 类描述符
- 属性描述符
- 方法描述符
- 常量
- JNI函数
- JNI函数总结
- 直接导出调用的接口函数
- Java虚拟机接口
- 在Native库中定义的函数
- JNIEnv接口
- JNI函数使用规范