在JNI中,你可以按照如下步骤调用构造函数,就像调用普通的对象实例函数那样。要获取MethodID,只需要使用"<init>作为函数名,将"V"作为函数返回值类型构造一个方法描述符即可。
你可以通过将方法ID传递给像NewObject这样的JNI函数来调用构造函数。以下函数实现了与JNI函数NewString同样的功能:从C缓冲区中存储的Unico字符串构造一个java.lang.String对象:
~~~
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
jstring MyNewString(JNIEnv *env, jchar *chars, jint len) {
jclass stringClass;
jmethodID cid;
jcharArray elemArr;
jstring result;
stringClass = (*env)->FindClass(env, "java/lang/String");
if(!stringClass){
return 0; /* exception thrown */
}
/* Get the method ID for the String(char[]) constructor */
cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V");
if(!cid) {
return 0; /* exception thrown */
}
/* Create a char[] that holds the string characters */
elemArr = (*env)->NewCharArray(env, len);
if(!elemArr) {
return 0; /* exception thrown */
}
(*env)->SetCharArrayRegion(env, elemArr, 0, len, chars);
/* Construct a java.lang.String */
result = (*env)->NewObject(env, stringClass, cid, elemArr);
/* Free local references */
(*env)->DeleteLocalRef(env, elemArr);
(*env)->DeleteLocalRef(env, stringClass);
return result;
}
#ifdef __cplusplus
}
#endif
~~~
这个函数还是有点复杂的,我来给大家详细解释下。
首先,FindClass查找到java.lang.String对应的类引用。
然后,GetMethodID返回了String类构造函数String(char[] chars)对应的方法ID,之后再调用NewCharArray分配了一个字符串数组,用于存储所有的字符串元素。最后JNI函数NewObject调用方法ID对应的构造函数,NewObject调用需要三部分参数:需要构建的对象对应的类引用, 构造函数方法ID, 构造函数需要的参数列表。
DeleteLocalRef函数调用允许虚拟机释放elemArr和stringClsss使用的资源.第5.2.1节会详细介绍为什么要使用DelectLocalRef以在什么时候使用.
String也是对象.这个实例也进一步说明了这点.然而,这个示例也带给我们一个问题,我们已经能够使用其他的JNI函数实现相同的功能,那为什JNI却要提供NewString这样的内置函数呢?根本原因是内置的字符串操作函数更加高效.字符串算得上使频最高的对象,所以专门为它提一套API支持也是值得的.
我们也可以使用CallNonvirtualVoidMethod函数调用构造函数,但是首先我们需要通过调用AllocObject函数创建一个未初始化的对象.上边实例中的NewObject调用:
`result = (*env)->NewObject(env,stringClass, cid, elemArr);`
可以用一个AllocObject和CallNonvirtualVoidMethod替代:
~~~
result = (*env)->AllocObject(env, stringClass);
if (result) {
(*env)->CallNonvirtualVoidMethod(env, result, stringClass, cid, elemArr);
/* we need to check for possible exceptions */
if((*env)->ExceptionCheck(env)) {
(*env)->DeleteLocalRef(env, result);
result = NULL;
}
}
~~~
AllocObject用于创建一个未初始化的对象,在使用的时候必须多加小心来保证一个构造函数在每个对象最多只能被调用一次.Native代码不应当在同一个对象上多次调用构造函数.
有的时候你会发现先分配一个未初始化对象,之后再在合适的时机调用构造函数会很有用(这个有点像c++的placement new).但是大多数情况下,你都应当使用NewObject来创建对象而不是使用更加容易产生错误的AllocObject/CallnonvirtualVoidMethod函数对.
- 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函数使用规范