第四章:JNI函数
本章作为JNI函数的参考部分。它提供了所有JNI函数的完整列表。它还展示了JNI函数表的确切布局。
请注意使用术语“必须”来描述对JNI程序员的限制。例如,当您看到某个JNI函数必须接收一个非NULL对象时,您有责任确保不会将NULL传递给该JNI函数。因此,JNI实现不需要在该JNI函数中执行NULL指针检查。在明确不允许的情况下传递NULL可能导致意外异常或致命崩溃。
定义可能同时返回NULL
并在错误时抛出异常的函数,可以选择仅返回NULL
以指示错误,但不抛出任何异常。例如,JNI实现可能认为“内存不足”条件是临时的,并且可能不希望抛出OutOfMemoryError
,因为这看起来是致命的(JDK API java.lang.Error
文档:“指示严重问题,合理的应用程序不应尝试捕获”)。
本章的部分内容改编自Netscape的JRI文档。
参考资料根据其用途将函数分组。参考部分按以下功能区域组织:
- 接口函数表
- 常量
- 版本信息
- 类操作
- 模块操作
- 线程操作
- 异常
- 全局和局部引用
- 弱全局引用
- 对象操作
- 访问对象的字段
- 调用实例方法
- 访问静态字段
- 调用静态方法
- 字符串操作
- 数组操作
- GetArrayLength
- NewObjectArray
- GetObjectArrayElement
- SetObjectArrayElement
- New<PrimitiveType>Array Routines
- Get<PrimitiveType>ArrayElements Routines
- Release<PrimitiveType>ArrayElements Routines
- Get<PrimitiveType>ArrayRegion Routines
- Set<PrimitiveType>ArrayRegion Routines
- GetPrimitiveArrayCritical, ReleasePrimitiveArrayCritical
- 注册本地方法
- 监视器操作
- NIO支持
- 反射支持
- Java VM接口
接口函数表
每个函数通过JNIEnv参数在固定偏移量处可访问。 JNIEnv类型是指向存储所有JNI函数指针的结构的指针。它的定义如下:
typedef const struct JNINativeInterface *JNIEnv;
虚拟机初始化函数表,如下面的代码示例所示。请注意,前三个条目保留用于与COM的未来兼容性。此外,我们在函数表的开始附近保留了一些额外的NULL
条目,以便例如,将来的与类相关的JNI操作可以添加在FindClass之后,而不是在表的末尾。
请注意,函数表可以在所有JNI接口指针之间共享。
const struct JNINativeInterface ... = {
NULL,
NULL,
NULL,
NULL,
GetVersion,
DefineClass,
FindClass,
FromReflectedMethod,
FromReflectedField,
ToReflectedMethod,
GetSuperclass,
IsAssignableFrom,
ToReflectedField,
Throw,
ThrowNew,
ExceptionOccurred,
ExceptionDescribe,
ExceptionClear,
FatalError,
PushLocalFrame,
PopLocalFrame,
NewGlobalRef,
DeleteGlobalRef,
DeleteLocalRef,
IsSameObject,
NewLocalRef,
EnsureLocalCapacity,
AllocObject,
NewObject,
NewObjectV,
NewObjectA,
GetObjectClass,
IsInstanceOf,
GetMethodID,
CallObjectMethod,
CallObjectMethodV,
CallObjectMethodA,
CallBooleanMethod,
CallBooleanMethodV,
CallBooleanMethodA,
CallByteMethod,
CallByteMethodV,
CallByteMethodA,
CallCharMethod,
CallCharMethodV,
CallCharMethodA,
CallShortMethod,
CallShortMethodV,
CallShortMethodA,
CallIntMethod,
CallIntMethodV,
CallIntMethodA,
CallLongMethod,
CallLongMethodV,
CallLongMethodA,
CallFloatMethod,
CallFloatMethodV,
CallFloatMethodA,
CallDoubleMethod,
CallDoubleMethodV,
CallDoubleMethodA,
CallVoidMethod,
CallVoidMethodV,
CallVoidMethodA,
CallNonvirtualObjectMethod,
CallNonvirtualObjectMethodV,
CallNonvirtualObjectMethodA,
CallNonvirtualBooleanMethod,
CallNonvirtualBooleanMethodV,
CallNonvirtualBooleanMethodA,
CallNonvirtualByteMethod,
CallNonvirtualByteMethodV,
CallNonvirtualByteMethodA,
CallNonvirtualCharMethod,
CallNonvirtualCharMethodV,
CallNonvirtualCharMethodA,
CallNonvirtualShortMethod,
CallNonvirtualShortMethodV,
CallNonvirtualShortMethodA,
CallNonvirtualIntMethod,
CallNonvirtualIntMethodV,
CallNonvirtualIntMethodA,
CallNonvirtualLongMethod,
CallNonvirtualLongMethodV,
CallNonvirtualLongMethodA,
CallNonvirtualFloatMethod,
CallNonvirtualFloatMethodV,
CallNonvirtualFloatMethodA,
CallNonvirtualDoubleMethod,
CallNonvirtualDoubleMethodV,
CallNonvirtualDoubleMethodA,
CallNonvirtualVoidMethod,
CallNonvirtualVoidMethodV,
CallNonvirtualVoidMethodA,
GetFieldID,
GetObjectField,
GetBooleanField,
GetByteField,
GetCharField,
GetShortField,
GetIntField,
GetLongField,
GetFloatField,
GetDoubleField,
SetObjectField,
SetBooleanField,
SetByteField,
SetCharField,
SetShortField,
SetIntField,
SetLongField,
SetFloatField,
SetDoubleField,
GetStaticMethodID,
CallStaticObjectMethod,
CallStaticObjectMethodV,
CallStaticObjectMethodA,
CallStaticBooleanMethod,
CallStaticBooleanMethodV,
CallStaticBooleanMethodA,
CallStaticByteMethod,
CallStaticByteMethodV,
CallStaticByteMethodA,
CallStaticCharMethod,
CallStaticCharMethodV,
CallStaticCharMethodA,
CallStaticShortMethod,
CallStaticShortMethodV,
CallStaticShortMethodA,
CallStaticIntMethod,
CallStaticIntMethodV,
CallStaticIntMethodA,
CallStaticLongMethod,
CallStaticLongMethodV,
CallStaticLongMethodA,
CallStaticFloatMethod,
CallStaticFloatMethodV,
CallStaticFloatMethodA,
CallStaticDoubleMethod,
CallStaticDoubleMethodV,
CallStaticDoubleMethodA,
CallStaticVoidMethod,
CallStaticVoidMethodV,
CallStaticVoidMethodA,
GetStaticFieldID,
GetStaticObjectField,
GetStaticBooleanField,
GetStaticByteField,
GetStaticCharField,
GetStaticShortField,
GetStaticIntField,
GetStaticLongField,
GetStaticFloatField,
GetStaticDoubleField,
SetStaticObjectField,
SetStaticBooleanField,
SetStaticByteField,
SetStaticCharField,
SetStaticShortField,
SetStaticIntField,
SetStaticLongField,
SetStaticFloatField,
SetStaticDoubleField,
NewString,
GetStringLength,
GetStringChars,
ReleaseStringChars,
NewStringUTF,
GetStringUTFLength,
GetStringUTFChars,
ReleaseStringUTFChars,
GetArrayLength,
NewObjectArray,
GetObjectArrayElement,
SetObjectArrayElement,
NewBooleanArray,
NewByteArray,
NewCharArray,
NewShortArray,
NewIntArray,
NewLongArray,
NewFloatArray,
NewDoubleArray,
GetBooleanArrayElements,
GetByteArrayElements,
GetCharArrayElements,
GetShortArrayElements,
GetIntArrayElements,
GetLongArrayElements,
GetFloatArrayElements,
GetDoubleArrayElements,
ReleaseBooleanArrayElements,
ReleaseByteArrayElements,
ReleaseCharArrayElements,
ReleaseShortArrayElements,
ReleaseIntArrayElements,
ReleaseLongArrayElements,
ReleaseFloatArrayElements,
ReleaseDoubleArrayElements,
GetBooleanArrayRegion,
GetByteArrayRegion,
GetCharArrayRegion,
GetShortArrayRegion,
GetIntArrayRegion,
GetLongArrayRegion,
GetFloatArrayRegion,
GetDoubleArrayRegion,
SetBooleanArrayRegion,
SetByteArrayRegion,
SetCharArrayRegion,
SetShortArrayRegion,
SetIntArrayRegion,
SetLongArrayRegion,
SetFloatArrayRegion,
SetDoubleArrayRegion,
RegisterNatives,
UnregisterNatives,
MonitorEnter,
MonitorExit,
GetJavaVM,
GetStringRegion,
GetStringUTFRegion,
GetPrimitiveArrayCritical,
ReleasePrimitiveArrayCritical,
GetStringCritical,
ReleaseStringCritical,
NewWeakGlobalRef,
DeleteWeakGlobalRef,
ExceptionCheck,
NewDirectByteBuffer,
GetDirectBufferAddress,
GetDirectBufferCapacity,
GetObjectRefType,
GetModule,
IsVirtualThread
};
常量
JNI API中使用的一些常用常量。
布尔值
#define JNI_FALSE 0
#define JNI_TRUE 1
返回码
用于JNI函数的一般返回值常量。
#define JNI_OK 0 /* 成功 */
#define JNI_ERR (-1) /* 未知错误 */
#define JNI_EDETACHED (-2) /* 线程与VM分离 */
#define JNI_EVERSION (-3) /* JNI版本错误 */
#define JNI_ENOMEM (-4) /* 内存不足 */
#define JNI_EEXIST (-5) /* VM已创建 */
#define JNI_EINVAL (-6) /* 无效参数 */
版本信息
GetVersion
jint GetVersion(JNIEnv *env);
返回本机方法接口的版本。对于Java SE Platform 21及更高版本,它返回JNI_VERSION_21
。以下表格显示了每个Java SE Platform版本中包含的JNI版本(对于旧版本的JNI,使用JDK版本而不是Java SE Platform):
Java SE Platform | JNI版本 |
---|---|
1.1 | JNI_VERSION_1_1 |
1.2 | JNI_VERSION_1_2 |
1.3 | JNI_VERSION_1_2 |
1.4 | JNI_VERSION_1_4 |
5.0 | JNI_VERSION_1_4 |
6 | JNI_VERSION_1_6 |
7 | JNI_VERSION_1_6 |
8 | JNI_VERSION_1_8 |
9 | JNI_VERSION_9 |
10 | JNI_VERSION_10 |
11 | JNI_VERSION_10 |
12 | JNI_VERSION_10 |
13 | JNI_VERSION_10 |
14 | JNI_VERSION_10 |
15 | JNI_VERSION_10 |
16 | JNI_VERSION_10 |
17 | JNI_VERSION_10 |
18 | JNI_VERSION_10 |
19 | JNI_VERSION_19 |
20 | JNI_VERSION_20 |
21+ | JNI_VERSION_21 |
链接:
JNIEnv接口函数表中的索引4。
参数:
env
:JNI接口指针,不得为NULL
。
返回:
返回高16位中的主要版本号和低16位中的次要版本号。
版本常量
#define JNI_VERSION_1_1 0x00010001
#define JNI_VERSION_1_2 0x00010002
#define JNI_VERSION_1_4 0x00010004
#define JNI_VERSION_1_6 0x00010006
#define JNI_VERSION_1_8 0x00010008
#define JNI_VERSION_9 0x00090000
#define JNI_VERSION_10 0x000a0000
#define JNI_VERSION_19 0x00130000
#define JNI_VERSION_20 0x00140000
#define JNI_VERSION_21 0x00150000
类操作
DefineClass
jclass DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize bufLen);
从原始类数据缓冲区加载类。在DefineClass调用返回后,包含原始类数据的缓冲区不会被VM引用,如果需要,可以丢弃它。
链接:
JNIEnv接口函数表中的索引5。
参数:
env
: JNI接口指针,不得为NULL
。
name
: 要定义的类或接口的名称。字符串以修改后的UTF-8编码。此值可以为NULL
,或者必须与类文件数据中编码的名称匹配。
loader
: 分配给定义类的类加载器。此值可以为NULL
,表示“空类加载器”(或“引导类加载器”)。
buf
: 包含.class
文件数据的缓冲区。NULL
值将导致ClassFormatError
。
bufLen
: 缓冲区长度。
返回值:
如果发生错误,则返回Java类对象或NULL
。
抛出:
ClassFormatError
: 如果类数据未指定有效类。
ClassCircularityError
: 如果类或接口将成为其自身的超类或超接口。
OutOfMemoryError
: 如果系统内存耗尽。
SecurityException
: 如果调用者尝试在“java”包树中定义类。
FindClass
jclass FindClass(JNIEnv *env, const char *name);
在JDK 1.1版本中,此函数加载本地定义的类。它搜索由CLASSPATH
环境变量指定的目录和zip文件,以查找指定名称的类。
自JDK 1.2以来,Java安全模型允许非系统类加载和调用本地方法。FindClass
定位与当前本地方法关联的类加载器;即声明本地方法的类的类加载器。如果本地方法属于系统类,则不涉及类加载器。否则,将调用适当的类加载器来加载、链接和初始化指定的类。
自JDK 1.2以来,当通过调用接口调用FindClass
时,不存在当前本地方法或其关联的类加载器。在这种情况下,将使用ClassLoader.getSystemClassLoader
的结果。这是虚拟机为应用程序创建的类加载器,能够定位java.class.path
属性中列出的类。
如果从库生命周期函数挂钩调用FindClass
,则类加载器确定如下:
- 对于
JNI_OnLoad
和JNI_OnLoad_L
,使用加载本地库的类的类加载器 - 对于
JNI_OnUnload
和JNI_OnUnload_L
,使用ClassLoader.getSystemClassLoader
返回的类加载器(因为在加载时使用的类加载器可能已不再存在)
name
参数是完全限定的类名或数组类型签名。例如,java.lang.String
类的完全限定类名为:
"java/lang/String"
java.lang.Object[]
数组类的数组类型签名为:
"[Ljava/lang/Object;"
链接:
JNIEnv接口函数表中的索引6。
参数:
env
: JNI接口指针,不得为NULL
。
name
: 完全限定的类名(即包名,由“/
”分隔,后跟类名)。如果名称以“[
”(数组签名字符)开头,则返回一个数组类。字符串以修改后的UTF-8编码。NULL
值可能导致NoClassDefFoundError
或崩溃。
返回值:
根据完全限定名称返回一个类对象,如果找不到类,则返回NULL
。
抛出:
ClassFormatError
: 如果类数据未指定有效类。
ClassCircularityError
: 如果类或接口将成为其自身的超类或超接口。
NoClassDefFoundError
: 如果找不到请求的类或接口的定义。
OutOfMemoryError
: 如果系统内存耗尽。
GetSuperclass
jclass GetSuperclass(JNIEnv *env, jclass clazz);
如果clazz
表示除Object
类之外的任何类,则此函数返回表示clazz
指定的类的超类的对象。
如果clazz
指定Object
类,或者clazz
表示一个接口,则此函数返回NULL
。
链接:
JNIEnv接口函数表中的索引10。
参数:
env
: JNI接口指针,不得为NULL
。
clazz
: Java类对象,不得为NULL
。
返回值:
返回由clazz
表示的类的超类,或NULL
。
IsAssignableFrom
jboolean IsAssignableFrom(JNIEnv *env, jclass clazz1, jclass clazz2);
确定clazz1
的对象是否可以安全地转换为clazz2
。
链接:
JNIEnv接口函数表中的索引11。
参数:
env
: JNI接口指针,不得为NULL
。
clazz1
: 第一个类参数,不得为NULL
。
clazz2
: 第二个类参数,不得为NULL
。
返回值:
如果以下任一情况为真,则返回JNI_TRUE
:
- 第一个和第二个类参数引用相同的Java类。
- 第一个类是第二个类的子类。
- 第一个类将第二个类作为其接口之一。
模块操作
GetModule
jobject GetModule(JNIEnv *env, jclass clazz);
返回类所属模块的java.lang.Module
对象。如果类不在命名模块中,则返回类加载器的未命名模块。如果类表示数组类型,则此函数返回元素类型的Module
对象。如果类表示原始类型或void
,则返回java.base
模块的Module
对象。
链接:
JNIEnv接口函数表中的索引233。
参数:
env
: JNI接口指针,不得为NULL
。
clazz
: Java类对象,不得为NULL
。
返回值:
返回类或接口所属的模块。
自从:
JDK/JRE 9
线程操作
IsVirtualThread
jboolean IsVirtualThread(JNIEnv *env, jobject obj);
测试对象是否为虚拟线程。
链接:
JNIEnv接口函数表中的索引234。
参数:
env
: JNI接口指针,不得为NULL
。
obj
: Java对象,可能是NULL
值。
返回值:
如果对象是虚拟线程,则返回JNI_TRUE。
自从:
JDK/JRE 21
异常
Throw
jint Throw(JNIEnv *env, jthrowable obj);
导致抛出java.lang.Throwable
对象。
链接:
JNIEnv接口函数表中的索引13。
参数:
env
: JNI接口指针,不得为NULL
。
obj
: java.lang.Throwable
对象,不得为NULL
。
返回值:
成功返回0;失败返回负值。
抛出:
java.lang.Throwable
对象obj
。
ThrowNew
jint ThrowNew(JNIEnv *env, jclass clazz, const char *message);
使用由message
指定的消息从指定类构造异常对象,并导致抛出该异常。
链接:
JNIEnv接口函数表中的索引14。
参数:
env
: JNI接口指针,不得为NULL
。
clazz
: java.lang.Throwable
的子类,不得为NULL
。
message
: 用于构造java.lang.Throwable
对象的消息。字符串以修改后的UTF-8编码。此值可以为NULL
。
返回值:
成功返回0;失败返回负值。
抛出:
新构造的java.lang.Throwable
对象。
ExceptionOccurred
jthrowable ExceptionOccurred(JNIEnv *env);
确定是否正在抛出异常。异常保持被抛出状态,直到本地代码调用ExceptionClear()
,或Java代码处理异常。
链接:
JNIEnv接口函数表中的索引15。
参数:
env
: JNI接口指针,不得为NULL
。
返回值:
返回当前正在被抛出的异常对象,如果当前没有异常被抛出,则返回NULL
。
ExceptionDescribe
void ExceptionDescribe(JNIEnv *env);
将异常和堆栈的回溯打印到系统错误报告通道,如stderr
。调用此函数的副作用是清除挂起的异常。这是为调试提供的便利程序。
链接:
JNIEnv接口函数表中的索引16。
参数:
env
: JNI接口指针,不得为NULL
。
ExceptionClear
void ExceptionClear(JNIEnv *env);
清除当前正在被抛出的任何异常。如果当前没有异常被抛出,则此例程不起作用。
链接:
JNIEnv接口函数表中的索引17。
参数:
env
: JNI接口指针,不得为NULL
。
FatalError
void FatalError(JNIEnv *env, const char *msg);
引发致命错误,并且不希望虚拟机恢复。此函数不返回。
链接:
JNIEnv接口函数表中的索引18。
参数:
env
: JNI接口指针,不得为NULL
。
msg
: 错误消息。字符串以修改后的UTF-8编码。可能是NULL
值。
ExceptionCheck
我们引入了一个方便的函数,用于检查是否存在未决异常,而不创建异常对象的本地引用。
jboolean ExceptionCheck(JNIEnv *env);
当存在挂起异常时返回JNI_TRUE
;否则返回JNI_FALSE
。
链接:
在JNIEnv接口函数表中的索引为228。
参数:
env
:JNI接口指针,不得为NULL
。
全局和局部引用
全局引用
NewGlobalRef
jobject NewGlobalRef(JNIEnv *env, jobject obj);
创建一个新的全局引用,指向obj
参数引用的对象。 obj
参数可以是全局引用或局部引用。 必须通过调用DeleteGlobalRef()
显式处理全局引用。
链接:
在JNIEnv接口函数表中的索引为21。
参数:
env
:JNI接口指针,不得为NULL
。
obj
:全局或局部引用。 可能是NULL
值,在这种情况下该函数将返回NULL
。
返回:
返回给定obj
的全局引用。
如果可能返回NULL
的情况包括:
obj
引用为null
- 系统内存不足
obj
是弱全局引用并且已被垃圾回收
DeleteGlobalRef
void DeleteGlobalRef(JNIEnv *env, jobject globalRef);
删除由globalRef
指向的全局引用。
链接:
在JNIEnv接口函数表中的索引为22。
参数:
env
:JNI接口指针,不得为NULL
。
globalRef
:全局引用。 可能是NULL
值,在这种情况下该函数不执行任何操作。
局部引用
局部引用在本机方法调用期间有效。 它们在本机方法返回后会自动释放。 每个局部引用都会消耗一定数量的Java虚拟机资源。 程序员需要确保本机方法不会过度分配局部引用。 尽管局部引用在本机方法返回到Java后会自动释放,但过度分配局部引用可能导致虚拟机在本机方法执行期间耗尽内存。
DeleteLocalRef
void DeleteLocalRef(JNIEnv *env, jobject localRef);
删除由localRef
指向的局部引用。
链接:
在JNIEnv接口函数表中的索引为23。
参数:
env
:JNI接口指针,不得为NULL
。
localRef
:局部引用。 在此处传递NULL
值时,该函数不执行任何操作。
注意:JDK/JRE 1.1提供了上述DeleteLocalRef
函数,以便程序员可以手动删除局部引用。 例如,如果本机代码遍历一个可能很大的对象数组,并在每次迭代中使用一个元素,则在下一次迭代中创建新的局部引用之前,最好删除不再使用的数组元素的局部引用。 从JDK/JRE 1.2开始,为局部引用的生命周期管理提供了另一组函数。 下面列出了四个函数。
EnsureLocalCapacity
jint EnsureLocalCapacity(JNIEnv *env, jint capacity);
确保当前线程中至少可以创建给定数量的局部引用。 成功返回0;否则返回负数并抛出OutOfMemoryError
。
在进入本机方法之前,虚拟机会自动确保至少可以创建16个局部引用。
出于向后兼容性的考虑,虚拟机会在确保容量之外分配局部引用。(作为调试支持,虚拟机可能会警告用户正在创建过多的局部引用。 在JDK中,程序员可以提供-verbose:jni
命令行选项以打开这些消息。) 如果在确保容量之外无法创建更多局部引用,虚拟机将调用FatalError
。
一些Java虚拟机实现可能选择限制最大capacity
,这可能导致函数返回错误(例如JNI_ERR
或JNI_EINVAL
)。 例如,HotSpot JVM实现使用-XX:+MaxJNILocalCapacity
标志(默认值:65536)。
链接:
在JNIEnv接口函数表中的索引为26。
参数:
env
:JNI接口指针,不得为NULL
。
capacity
:所需局部引用的最小数量。 必须为>= 0。
返回:
成功时返回JNI_OK
。
自版本:
JDK/JRE 1.2
PushLocalFrame
jint PushLocalFrame(JNIEnv *env, jint capacity);
创建一个新的局部引用帧,在其中至少可以创建给定数量的局部引用。 成功返回0,失败时返回负数并挂起OutOfMemoryError
。
请注意,已在先前的局部帧中创建的局部引用在当前局部帧中仍然有效。
与EnsureLocalCapacity
一样,一些Java虚拟机实现可能选择限制最大capacity
,这可能导致函数返回错误。
链接:
在JNIEnv接口函数表中的索引为19。
参数:
env
:JNI接口指针,不得为NULL
。
capacity
:所需局部引用的最小数量。 必须为> 0。
返回:
成功时返回JNI_OK
。
自版本:
JDK/JRE 1.2
PopLocalFrame
jobject PopLocalFrame(JNIEnv *env, jobject result);
弹出当前局部引用帧,释放所有局部引用,并为给定的result
对象返回上一个局部引用帧中的局部引用。
如果不需要返回到先前帧的引用,则将result
传递为NULL
。
链接:
在JNIEnv接口函数表中的索引为20。
参数:
env
:JNI接口指针,不得为NULL
。
result
:要传递给先前局部引用帧的对象,可能为NULL
。
返回:
为给定的result
对象返回上一个局部引用帧中的局部引用,如果给定的result
对象为NULL
,则返回NULL
。
自版本:
JDK/JRE 1.2
NewLocalRef
jobject NewLocalRef(JNIEnv *env, jobject ref);
创建一个新的局部引用,引用与ref
相同的对象。 给定的ref
可以是全局引用、局部引用或NULL
。 如果ref
引用为null
,则返回NULL
。
链接:
在JNIEnv接口函数表中的索引为25。
参数:
env
:JNI接口指针,不得为NULL
。
ref
:要为其创建新局部引用的对象引用。 可能是NULL
值。
返回:
返回一个引用与ref
相同的对象的新局部引用。
如果可能返回NULL
的情况包括:
ref
引用为null
- 系统内存不足
ref
是弱全局引用并且已被垃圾回收
自版本:
JDK/JRE 1.2
弱全局引用
弱全局引用是一种特殊类型的全局引用。 与普通全局引用不同,弱全局引用允许底层Java对象被垃圾回收。 弱全局引用可以在任何需要全局或局部引用的情况下使用。
弱全局引用与Java虚拟引用(java.lang.ref.PhantomReference
)相关。 对特定对象的弱全局引用在确定对象是否虚引用可达(请参阅java.lang.ref
)时被视为引用该对象的虚引用。 当垃圾回收器清除引用同一对象的PhantomReference
时,这样的弱全局引用将在同一时间变得等效于NULL
。
由于垃圾回收可能在本机方法运行时发生,因此由弱全局引用引用的对象可以随时被释放。 虽然弱全局引用可以在需要全局引用的地方使用,但通常不适合这样做,因为它们可能在没有通知的情况下变得等效于NULL
。
IsSameObject
可用于比较弱全局引用与非NULL
局部或全局引用。 如果对象相同,则只要另一个引用未被删除,弱全局引用就不会变得等效于NULL
。
IsSameObject
还可用于将弱全局引用与NULL
进行比较,以确定底层对象是否已被释放。 但是,程序员不应依赖此检查来确定将来的JNI函数调用中是否可以使用弱全局引用(作为非NULL
引用),因为介入的垃圾回收可能会更改弱全局引用。
相反,建议使用JNI函数NewLocalRef
或NewGlobalRef
获取对底层对象的(强)局部或全局引用。 如果对象已被释放,这些函数将返回NULL
。 否则,新引用将防止底层对象被释放。 如果新引用非NULL
,则可以用于访问底层对象,并在不再需要此访问时删除。
NewWeakGlobalRef
jweak NewWeakGlobalRef(JNIEnv *env, jobject obj);
创建一个新的弱全局引用。 弱全局引用不会阻止给定对象的垃圾回收。 可以使用IsSameObject
来测试引用的对象是否已被释放。 如果obj
引用为null
,或者obj
是弱全局引用,或者虚拟机内存不足,则返回NULL
。 如果虚拟机内存不足,将抛出OutOfMemoryError
。
链接:
在JNIEnv接口函数表中的索引为226。
参数:
env
:JNI接口指针,不得为NULL
。
obj
:要为其创建全局弱引用的对象。
返回:
返回给定obj
的全局弱引用。
如果发生以下情况可能返回NULL
:
obj
引用为null
- 系统内存耗尽
obj
是一个弱全局引用,并且已经被垃圾回收
抛出:
如果系统内存耗尽,则抛出OutOfMemoryError
。
自从:
JDK/JRE 1.2
DeleteWeakGlobalRef
void DeleteWeakGlobalRef(JNIEnv *env, jweak obj);
删除给定弱全局引用所需的VM资源。
链接:
在JNIEnv接口函数表中的索引227。
参数:
env
:JNI接口指针,不得为NULL
。
obj
:要删除的全局弱引用。如果传递NULL
,此函数将不执行任何操作。
自从:
JDK/JRE 1.2
对象操作
AllocObject
jobject AllocObject(JNIEnv *env, jclass clazz);
分配一个新的Java对象而不调用对象的任何构造函数。返回对象的引用。
注意:Java语言规范,“实现终结” (JLS §12.6.1) 规定:“对象o在其构造函数调用了o的Object构造函数并且该调用成功完成之前,对象o不是可终结的”。由于AllocObject()不调用构造函数,使用此函数创建的对象不符合终结条件。
clazz参数不得引用数组类。
链接:
在JNIEnv接口函数表中的索引27。
参数:
env
:JNI接口指针,不得为NULL
。
clazz
:Java类对象的引用,不得为NULL
。
返回:
返回一个Java对象,如果无法构造对象则返回NULL
。
抛出:
InstantiationException
:如果类是接口或抽象类。
OutOfMemoryError
:如果系统内存耗尽。
NewObject, NewObjectA, NewObjectV
jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);
jobject NewObjectA(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
jobject NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
构造一个新的Java对象。方法ID指示要调用的构造方法。此ID必须通过使用GetMethodID()
并将<init>
作为方法名和void
(V
)作为返回类型来获取。
clazz
参数不得引用数组类。
NewObject
程序员将要传递给构造函数的所有参数立即放在methodID
参数之后。 NewObject()
接受这些参数并将它们传递给程序员希望调用的Java方法。
链接:
在JNIEnv接口函数表中的索引28。
NewObjectA
程序员将要传递给构造函数的所有参数放在紧随methodID
参数的jvalues
数组中。 NewObjectA()
接受此数组中的参数,并将它们传递给程序员希望调用的Java方法。
链接:
在JNIEnv接口函数表中的索引30。
NewObjectV
程序员将要传递给构造函数的所有参数放在一个类型为va_list
的args
参数中,紧随methodID
参数。 NewObjectV()
接受这些参数,并将它们传递给程序员希望调用的Java方法。
链接:
在JNIEnv接口函数表中的索引29。
参数:
env
:JNI接口指针,不得为NULL
。
clazz
:Java类对象的引用,不得为NULL
。
methodID
:构造函数的方法ID。
NewObject的额外参数:
构造函数的参数。
NewObjectA的额外参数:
args
:构造函数的参数数组。
NewObjectV的额外参数:
args
:构造函数的va_list
参数。
返回:
返回一个Java对象,如果无法构造对象则返回NULL
。
抛出:
InstantiationException
:如果类是接口或抽象类。
OutOfMemoryError
:如果系统内存耗尽。
构造函数抛出的任何异常。
GetObjectClass
jclass GetObjectClass(JNIEnv *env, jobject obj);
返回对象的类。
链接:
在JNIEnv接口函数表中的索引31。
参数:
env
:JNI接口指针,不得为NULL
。
obj
:Java对象,不得为NULL
。
返回:
返回一个Java类对象。
GetObjectRefType
jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj);
返回由obj
参数引用的对象的类型。参数obj
可以是本地、全局或弱全局引用,也可以是NULL
。
链接:
在JNIEnv接口函数表中的索引232。
参数:
env
:JNI接口指针,不得为NULL
。
obj
:本地、全局或弱全局引用。
返回:
函数GetObjectRefType
返回定义为jobjectRefType
的以下枚举值之一:
JNIInvalidRefType = 0
JNILocalRefType = 1
JNIGlobalRefType = 2
JNIWeakGlobalRefType = 3
如果参数obj
是弱全局引用类型,则返回值将是JNIWeakGlobalRefType
。
如果参数obj
是全局引用类型,则返回值将是JNIGlobalRefType
。
如果参数obj
是本地引用类型,则返回值将是JNILocalRefType
。
如果obj
参数不是有效引用,则此函数的返回值将是JNIInvalidRefType
。
无效引用是指不是有效句柄的引用。也就是说,obj
指针地址不指向从VM中的任何Ref创建函数分配的内存位置或从JNI函数返回的内存位置。
因此,NULL
将是一个无效引用,GetObjectRefType(env,NULL)
将返回JNIInvalidRefType
。
另一方面,空引用是指指向空值的引用,将返回空引用最初创建的引用类型。
GetObjectRefType
不能用于已删除的引用。
由于引用通常实现为指向可能由VM中的任何引用分配服务重新使用的内存数据结构的指针,一旦删除,未指定GetObjectRefType
将返回什么值。
自从:
JDK/JRE 1.6
IsInstanceOf
jboolean IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz);
测试对象是否是类的实例。
链接:
在JNIEnv接口函数表中的索引32。
参数:
env
:JNI接口指针,不得为NULL
。
obj
:Java对象,可能是NULL
值。
clazz
:Java类对象,不得为NULL
。
返回:
如果obj
可以转换为clazz
,则返回JNI_TRUE
;否则返回JNI_FALSE
。 NULL
对象可以转换为任何类。
IsSameObject
jboolean IsSameObject(JNIEnv *env, jobject ref1, jobject ref2);
测试两个引用是否指向相同的Java对象。
链接:
在JNIEnv接口函数表中的索引24。
参数:
env
:JNI接口指针,不得为NULL
。
ref1
:Java对象,可能为NULL
。
ref2
:Java对象,可能为NULL
。
返回:
如果ref1
和ref2
指向相同的Java对象,或者两者都为NULL
,则返回JNI_TRUE
;否则返回JNI_FALSE
。
访问对象的字段
GetFieldID
jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
返回类的实例(非静态)字段的字段ID。字段由其名称和签名指定。Get<type>Field和Set<type>Field系列访问器函数使用字段ID来检索对象字段。
GetFieldID()
导致未初始化的类被初始化。
GetFieldID()
不能用于获取数组的长度字段。请改用GetArrayLength()
。
链接:
在JNIEnv接口函数表中的索引94。
参数:
env
:JNI接口指针,不得为NULL
。
clazz
:Java类对象,不得为NULL
。
name
:以0结尾的修改过的UTF-8字符串中的字段名称,不得为NULL
。
sig
:以0结尾的修改过的UTF-8字符串中的字段签名,不得为NULL
。
返回:
返回字段ID,如果操作失败则返回NULL
。
抛出:
NoSuchFieldError
:如果找不到指定的字段。
ExceptionInInitializerError
:如果类初始化程序由于异常而失败。
OutOfMemoryError
:如果系统内存耗尽。
Get<type>Field Routines
NativeType Get<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID);
此系列访问器例程返回对象的实例(非静态)字段的值。要访问的字段由调用GetFieldID()
获得的字段ID指定。
以下表格描述了Get<type>Field例程名称和结果类型。您应该将Get<type>Field中的type替换为字段的Java类型,或者使用表中的实际例程名称,并将NativeType替换为该例程的相应本机类型。
Get<type>Field 例程名称 | 本机类型 |
---|---|
GetObjectField() |
jobject |
GetBooleanField() |
jboolean |
GetByteField() |
jbyte |
GetCharField() |
jchar |
GetShortField() |
jshort |
GetIntField() |
jint |
GetLongField() |
jlong |
GetFloatField() |
jfloat |
GetDoubleField() |
jdouble |
链接:
JNIEnv接口函数表中的索引:
Get<type>Field 例程名称 | 索引 |
---|---|
GetObjectField() |
95 |
GetBooleanField() |
96 |
GetByteField() |
97 |
GetCharField() |
98 |
GetShortField() |
99 |
GetIntField() |
100 |
GetLongField() |
101 |
GetFloatField() |
102 |
GetDoubleField() |
103 |
参数:
env
:JNI接口指针,不得为NULL
。
obj
:Java对象,不得为NULL
。
fieldID
:有效的字段ID。
返回:
返回字段的内容。
Set<type>Field 例程
void
Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID,
NativeType value);
这个访问器例程系列用于设置对象的实例(非静态)字段的值。要访问的字段由调用GetFieldID()
获得的字段ID指定。
以下表格描述了Set<type>Field例程名称和值类型。您应该将Set<type>Field中的type替换为字段的Java类型,或者使用表中的实际例程名称,并将NativeType替换为该例程的相应本机类型。
Set<type>Field 例程 | 本机类型 |
---|---|
SetObjectField() |
jobject |
SetBooleanField() |
jboolean |
SetByteField() |
jbyte |
SetCharField() |
jchar |
SetShortField() |
jshort |
SetIntField() |
jint |
SetLongField() |
jlong |
SetFloatField() |
jfloat |
SetDoubleField() |
jdouble |
链接:
JNIEnv接口函数表中的索引。
Set<type>Field 例程 | 索引 |
---|---|
SetObjectField() |
104 |
SetBooleanField() |
105 |
SetByteField() |
106 |
SetCharField() |
107 |
SetShortField() |
108 |
SetIntField() |
109 |
SetLongField() |
110 |
SetFloatField() |
111 |
SetDoubleField() |
112 |
参数:
env
:JNI接口指针,不得为NULL
。
obj
:Java对象,不得为NULL
。
fieldID
:有效的字段ID。
value
:字段的新值。
调用实例方法
在从本机代码调用方法时,请注意这些方法是否可能是调用者敏感的。
GetMethodID
jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
返回类或接口的实例(非静态)方法的方法ID。该方法可以在clazz
的超类型之一中定义,并由clazz
继承。该方法由其名称和签名确定。
GetMethodID()
导致一个未初始化的类被初始化。
要获取构造函数的方法ID,请将<init>
作为方法名称并将void
(V
)作为返回类型。
链接:
JNIEnv接口函数表中的索引33。
参数:
env
:JNI接口指针,不得为NULL
。
clazz
:Java类对象,不得为NULL
。
name
:方法名称,以0结尾的修改过的UTF-8字符串,不得为NULL
。
sig
:方法签名,以0结尾的修改过的UTF-8字符串,不得为NULL
。
返回:
返回方法ID,如果找不到指定的方法则返回NULL
。
抛出:
NoSuchMethodError
:如果找不到指定的方法。
ExceptionInInitializerError
:如果类初始化程序由于异常而失败。
OutOfMemoryError
:如果系统内存耗尽。
Call<type>Method 例程,Call<type>MethodA 例程,Call<type>MethodV 例程
NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);
NativeType Call<type>MethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
NativeType Call<type>MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
这三个操作系列的方法用于从本机方法调用Java实例方法。它们在向调用的方法传递参数的机制上有所不同。
这些操作系列在Java对象上调用一个实例(非静态)方法,根据指定的方法ID。必须通过调用GetMethodID()
来获取methodID
参数。
当这些函数用于调用私有方法和构造函数时,方法ID必须从obj
的真实类派生,而不是从其超类之一派生。
调用<type>方法例程
程序员将要传递给方法的所有参数立即放在methodID
参数之后。 Call<type>Method例程接受这些参数并将它们传递给程序员希望调用的Java方法。
调用<type>MethodA例程
程序员将要传递给方法的所有参数放在紧随methodID
参数的jvalues
数组中。 Call<type>MethodA例程接受此数组中的参数,然后将它们传递给程序员希望调用的Java方法。
调用<type>MethodV例程
程序员将要传递给方法的所有参数放在一个类型为va_list
的args
参数中,该参数紧随methodID
参数。 Call<type>MethodV例程接受这些参数,然后将它们传递给程序员希望调用的Java方法。
以下表格根据它们的结果类型描述了每个方法调用例程。您应该在Call<type>Method中用Java方法的Java类型替换type(或使用表中的实际方法调用例程名称之一),并用相应的本机类型替换NativeType。
Call<type>Method例程名称 | 本机类型 |
---|---|
CallVoidMethod() CallVoidMethodA() CallVoidMethodV() |
void |
CallObjectMethod() CallObjectMethodA() CallObjectMethodV() |
jobject |
CallBooleanMethod() CallBooleanMethodA() CallBooleanMethodV() |
jboolean |
CallByteMethod() CallByteMethodA() CallByteMethodV() |
jbyte |
CallCharMethod() CallCharMethodA() CallCharMethodV() |
jchar |
CallShortMethod() CallShortMethodA() CallShortMethodV() |
jshort |
CallIntMethod() CallIntMethodA() CallIntMethodV() |
jint |
CallLongMethod() CallLongMethodA() CallLongMethodV() |
jlong |
CallFloatMethod() CallFloatMethodA() CallFloatMethodV() |
jfloat |
CallDoubleMethod() CallDoubleMethodA() CallDoubleMethodV() |
jdouble |
链接:
JNIEnv接口函数表中的索引:
Call<type>Method例程名称 | 索引 |
---|---|
CallVoidMethod() CallVoidMethodA() CallVoidMethodV() |
61 63 62 |
CallObjectMethod() CallObjectMethodA() CallObjectMethodV() |
34 36 35 |
CallBooleanMethod() CallBooleanMethodA() CallBooleanMethodV() |
37 39 38 |
CallByteMethod() CallByteMethodA() CallByteMethodV() |
40 42 41 |
CallCharMethod() CallCharMethodA() CallCharMethodV() |
43 45 44 |
CallShortMethod() CallShortMethodA() CallShortMethodV() |
46 48 47 |
CallIntMethod() CallIntMethodA() CallIntMethodV() |
49 51 50 |
CallLongMethod() CallLongMethodA() CallLongMethodV() |
52 54 53 |
CallFloatMethod() CallFloatMethodA() CallFloatMethodV() |
55 57 56 |
CallDoubleMethod() CallDoubleMethodA() CallDoubleMethodV() |
58 60 59 |
参数:
env
:JNI接口指针,不得为NULL
。
obj
:Java对象,不得为NULL
。
methodID
:有效的方法ID。
调用<type>方法例程的附加参数:
Java方法的参数。
调用<type>MethodA例程的附加参数:
args
:参数数组。
调用<type>MethodV例程的附加参数:
args
:参数的va_list
。
返回:
返回调用Java方法的结果。
抛出:
在执行Java方法期间引发的异常。
调用非虚拟<type>方法例程,调用非虚拟<type>MethodA例程,调用非虚拟<type>MethodV例程
NativeType CallNonvirtual<type>Method(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
NativeType CallNonvirtual<type>MethodA(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue *args);
NativeType CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args);
这些操作系列根据指定的类和方法ID在Java对象上调用一个实例(非静态)方法。 methodID
参数必须通过在类clazz
上调用GetMethodID()
来获取。
CallNonvirtual<type>Method系列例程和Call<type>Method系列例程是不同的。 Call<type>Method例程根据对象的类或接口调用方法,而CallNonvirtual<type>Method例程根据类调用方法,该类由clazz
参数指定,从中获取方法ID。 方法ID必须从对象的真实类或其超类之一获取。
CallNonvirtual<type>Method例程是在Java 8中引入的调用“默认接口方法”的机制。
调用非虚拟<type>方法例程
程序员将要传递给方法的所有参数立即放在methodID
参数之后。 CallNonvirtual<type>Method例程接受这些参数并将它们传递给程序员希望调用的Java方法。
调用非虚拟<type>MethodA例程
程序员将要传递给方法的所有参数放在紧随methodID
参数的jvalues
数组中。 CallNonvirtual<type>MethodA例程接受此数组中的参数,并将它们传递给程序员希望调用的Java方法。
调用非虚拟<type>MethodV例程
程序员将要传递给方法的所有参数放在一个类型为va_list
的args
参数中,该参数紧随methodID
参数。 CallNonvirtualMethodV例程接受这些参数,并将它们传递给程序员希望调用的Java方法。
以下表格根据它们的结果类型描述了每个方法调用例程。您应该在CallNonvirtual<type>Method中用方法的Java类型替换type,或使用表中的实际方法调用例程名称之一,并用相应的本机类型替换NativeType。
CallNonvirtual<type>Method例程名称 | 本地类型 |
---|---|
CallNonvirtualVoidMethod() CallNonvirtualVoidMethodA() CallNonvirtualVoidMethodV() |
void |
CallNonvirtualObjectMethod() CallNonvirtualObjectMethodA() CallNonvirtualObjectMethodV() |
jobject |
CallNonvirtualBooleanMethod() CallNonvirtualBooleanMethodA() CallNonvirtualBooleanMethodV() |
jboolean |
CallNonvirtualByteMethod() CallNonvirtualByteMethodA() CallNonvirtualByteMethodV() |
jbyte |
CallNonvirtualCharMethod() CallNonvirtualCharMethodA() CallNonvirtualCharMethodV() |
jchar |
CallNonvirtualShortMethod() CallNonvirtualShortMethodA() CallNonvirtualShortMethodV() |
jshort |
CallNonvirtualIntMethod() CallNonvirtualIntMethodA() CallNonvirtualIntMethodV() |
jint |
CallNonvirtualLongMethod() CallNonvirtualLongMethodA() CallNonvirtualLongMethodV() |
jlong |
CallNonvirtualFloatMethod() CallNonvirtualFloatMethodA() CallNonvirtualFloatMethodV() |
jfloat |
CallNonvirtualDoubleMethod() CallNonvirtualDoubleMethodA() CallNonvirtualDoubleMethodV() |
jdouble |
链接:
JNIEnv接口函数表中的索引。
CallNonvirtual<type>Method例程名称 | 索引 |
---|---|
CallNonvirtualVoidMethod() CallNonvirtualVoidMethodA() CallNonvirtualVoidMethodV() |
91 93 92 |
CallNonvirtualObjectMethod() CallNonvirtualObjectMethodA() CallNonvirtualObjectMethodV() |
64 66 65 |
CallNonvirtualBooleanMethod() CallNonvirtualBooleanMethodA() CallNonvirtualBooleanMethodV() |
67 69 68 |
CallNonvirtualByteMethod() CallNonvirtualByteMethodA() CallNonvirtualByteMethodV() |
70 72 71 |
CallNonvirtualCharMethod() CallNonvirtualCharMethodA() CallNonvirtualCharMethodV() |
73 75 74 |
CallNonvirtualShortMethod() CallNonvirtualShortMethodA() CallNonvirtualShortMethodV() |
76 78 77 |
CallNonvirtualIntMethod() CallNonvirtualIntMethodA() CallNonvirtualIntMethodV() |
79 81 80 |
CallNonvirtualLongMethod() CallNonvirtualLongMethodA() CallNonvirtualLongMethodV() |
82 84 83 |
CallNonvirtualFloatMethod() CallNonvirtualFloatMethodA() CallNonvirtualFloatMethodV() |
85 87 86 |
CallNonvirtualDoubleMethod() CallNonvirtualDoubleMethodA() CallNonvirtualDoubleMethodV() |
88 90 89 |
参数:
env
: JNI接口指针,不得为NULL
。
clazz
: 一个Java类,不得为NULL
。
obj
: 一个Java对象,不得为NULL
。
methodID
: 一个方法ID。
CallNonvirtual<type>Method例程的额外参数:
Java方法的参数。
CallNonvirtual<type>MethodA例程的额外参数:
args
: 一个参数数组。
CallNonvirtual<type>MethodV例程的额外参数:
args
: 一个参数的va_list
。
返回:
返回调用Java方法的结果。
抛出:
在执行Java方法时引发的异常。
访问静态字段
GetStaticFieldID
jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
返回类的静态字段的字段ID。字段由其名称和签名指定。GetStatic<type>Field和SetStatic<type>Field访问器函数系列使用字段ID来检索静态字段。
GetStaticFieldID()
导致一个未初始化的类被初始化。
链接:
JNIEnv接口函数表中的索引144。
参数:
env
: JNI接口指针,不得为NULL
。
clazz
: 一个Java类对象,不得为NULL
。
name
: 以0结尾的修改过的UTF-8字符串中的静态字段名称,不得为NULL
。
sig
: 以0结尾的修改过的UTF-8字符串中的字段签名,不得为NULL
。
返回:
返回字段ID,如果找不到指定的静态字段,则返回NULL
。
抛出:
NoSuchFieldError
: 如果找不到指定的静态字段。
ExceptionInInitializerError
: 如果类初始化程序由于异常而失败。
OutOfMemoryError
: 如果系统内存不足。
GetStatic<type>Field例程
NativeType GetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID);
这个访问器例程系列返回对象的静态字段的值。要访问的字段由字段ID指定,通过调用GetStaticFieldID()
获得。
以下表格描述了获取例程名称和结果类型的系列。您应该在GetStatic<type>Field中用Java字段的类型或表中的实际静态字段访问器例程名称之一替换type,并用该例程的相应本地类型替换NativeType。
GetStatic<type>Field例程名称 | 本地类型 |
---|---|
GetStaticObjectField() |
jobject |
GetStaticBooleanField() |
jboolean |
GetStaticByteField() |
jbyte |
GetStaticCharField() |
jchar |
GetStaticShortField() |
jshort |
GetStaticIntField() |
jint |
GetStaticLongField() |
jlong |
GetStaticFloatField() |
jfloat |
GetStaticDoubleField() |
jdouble |
链接:
JNIEnv接口函数表中的索引。
GetStatic<type>Field 例程名称 | 索引 |
---|---|
GetStaticObjectField() |
145 |
GetStaticBooleanField() |
146 |
GetStaticByteField() |
147 |
GetStaticCharField() |
148 |
GetStaticShortField() |
149 |
GetStaticIntField() |
150 |
GetStaticLongField() |
151 |
GetStaticFloatField() |
152 |
GetStaticDoubleField() |
153 |
参数:
env
: JNI接口指针,不得为NULL
。
clazz
: Java类对象,不得为NULL
。
fieldID
: 有效的静态字段ID。
返回:
返回静态字段的内容。
SetStatic<type>Field 例程
void
SetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID,
NativeType value);
这个访问器例程系列设置对象的静态字段的值。要访问的字段由字段ID指定,该字段ID通过调用GetStaticFieldID()
获得。
以下表格描述了设置例程名称和值类型。您应该将SetStatic<type>Field中的type替换为字段的Java类型,或者从表中选择一个实际的设置静态字段例程名称,并将NativeType替换为该例程的相应本机类型。
SetStatic<type>Field 例程名称 | NativeType |
---|---|
SetStaticObjectField() |
jobject |
SetStaticBooleanField() |
jboolean |
SetStaticByteField() |
jbyte |
SetStaticCharField() |
jchar |
SetStaticShortField() |
jshort |
SetStaticIntField() |
jint |
SetStaticLongField() |
jlong |
SetStaticFloatField() |
jfloat |
SetStaticDoubleField() |
jdouble |
链接:
JNIEnv接口函数表中的索引。
SetStatic<type>Field 例程名称 | 索引 |
---|---|
SetStaticObjectField() |
154 |
SetStaticBooleanField() |
155 |
SetStaticByteField() |
156 |
SetStaticCharField() |
157 |
SetStaticShortField() |
158 |
SetStaticIntField() |
159 |
SetStaticLongField() |
160 |
SetStaticFloatField() |
161 |
SetStaticDoubleField() |
162 |
参数:
env
: JNI接口指针,不得为NULL
。
clazz
: Java类对象,不得为NULL
。
fieldID
: 有效的静态字段ID。
value
: 字段的新值。
调用静态方法
在调用本机代码中的方法时,请注意这些方法是否可能是调用者敏感的。
GetStaticMethodID
jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
返回类的静态方法的方法ID。该方法由其名称和签名指定。
GetStaticMethodID()
导致未初始化的类被初始化。
链接:
JNIEnv接口函数表中的索引113。
参数:
env
: JNI接口指针,不得为NULL
。
clazz
: Java类对象,不得为NULL
。
name
: 以0结尾的修改过的UTF-8字符串中的静态方法名称,不得为NULL
。
sig
: 以0结尾的修改过的UTF-8字符串中的方法签名,不得为NULL
。
返回:
返回方法ID,如果操作失败则返回NULL
。
抛出:
NoSuchMethodError
: 如果找不到指定的静态方法。
ExceptionInInitializerError
: 如果类初始化程序由于异常而失败。
OutOfMemoryError
: 如果系统内存耗尽。
调用静态<type>方法 例程, 调用静态<type>方法A 例程, 调用静态<type>方法V 例程
NativeType CallStatic<type>Method(JNIEnv *env, jclass clazz, jmethodID methodID, ...);
NativeType CallStatic<type>MethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
NativeType CallStatic<type>MethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
这个操作系列根据指定的方法ID在Java对象上调用静态方法。 methodID
参数必须通过调用GetStaticMethodID()
获得。
方法ID必须派生自clazz
,而不是从其超类派生。
调用静态<type>方法 例程
程序员应该将要传递给方法的所有参数放在methodID
参数后面。 CallStatic<type>Method例程接受这些参数并将它们传递给程序员希望调用的Java方法。
调用静态<type>方法A 例程
程序员应该将方法的所有参数放在args
数组中,该数组紧随methodID
参数。 CallStaticMethodA例程接受此数组中的参数,并依次将它们传递给程序员希望调用的Java方法。
调用静态<type>方法V 例程
程序员应该将方法的所有参数放在类型为va_list
的args
参数中,该参数紧随methodID
参数。 CallStaticMethodV例程接受这些参数,并依次将它们传递给程序员希望调用的Java方法。
以下表格根据它们的结果类型描述了每个方法调用例程。您应该将CallStatic<type>Method中的type替换为方法的Java类型,或者从表中选择一个实际的方法调用例程名称,并将NativeType替换为该例程的相应本机类型。
CallStatic<type>Method 例程名称 | 本地类型 |
---|---|
CallStaticVoidMethod() CallStaticVoidMethodA() CallStaticVoidMethodV() |
void |
CallStaticObjectMethod() CallStaticObjectMethodA() CallStaticObjectMethodV() |
jobject |
CallStaticBooleanMethod() CallStaticBooleanMethodA() CallStaticBooleanMethodV() |
jboolean |
CallStaticByteMethod() CallStaticByteMethodA() CallStaticByteMethodV() |
jbyte |
CallStaticCharMethod() CallStaticCharMethodA() CallStaticCharMethodV() |
jchar |
CallStaticShortMethod() CallStaticShortMethodA() CallStaticShortMethodV() |
jshort |
CallStaticIntMethod() CallStaticIntMethodA() CallStaticIntMethodV() |
jint |
CallStaticLongMethod() CallStaticLongMethodA() CallStaticLongMethodV() |
jlong |
CallStaticFloatMethod() CallStaticFloatMethodA() CallStaticFloatMethodV() |
jfloat |
CallStaticDoubleMethod() CallStaticDoubleMethodA() CallStaticDoubleMethodV() |
jdouble |
链接:
JNIEnv接口函数表中的索引。
CallStatic<type>Method 例程名称 | 索引 |
---|---|
CallStaticVoidMethod() CallStaticVoidMethodA() CallStaticVoidMethodV() |
141 143 142 |
CallStaticObjectMethod() CallStaticObjectMethodA() CallStaticObjectMethodV() |
114 116 115 |
CallStaticBooleanMethod() CallStaticBooleanMethodA() CallStaticBooleanMethodV() |
117 119 118 |
CallStaticByteMethod() CallStaticByteMethodA() CallStaticByteMethodV() |
120 122 121 |
CallStaticCharMethod() CallStaticCharMethodA() CallStaticCharMethodV() |
123 125 124 |
CallStaticShortMethod() CallStaticShortMethodA() CallStaticShortMethodV() |
126 128 127 |
CallStaticIntMethod() CallStaticIntMethodA() CallStaticIntMethodV() |
129 131 130 |
CallStaticLongMethod() CallStaticLongMethodA() CallStaticLongMethodV() |
132 134 133 |
CallStaticFloatMethod() CallStaticFloatMethodA() CallStaticFloatMethodV() |
135 137 136 |
CallStaticDoubleMethod() CallStaticDoubleMethodA() CallStaticDoubleMethodV() |
138 140 139 |
参数:
env
: JNI接口指针,不得为NULL
。
clazz
: Java类对象,不得为NULL
。
methodID
: 有效的静态方法ID。
CallStatic<type>Method例程的附加参数:
静态方法的参数。
CallStatic<type>MethodA例程的附加参数:
args
: 参数数组。
CallStatic<type>MethodV例程的附加参数:
args
: 参数的va_list
。
返回:
返回调用静态Java方法的结果。
抛出:
执行Java方法时引发的异常。
字符串操作
此规范不对JVM如何内部表示Java字符串做出假设。从这些操作返回的字符串:
GetStringChars()
GetStringUTFChars()
GetStringRegion()
GetStringUTFRegion()
GetStringCritical()
因此不需要以NULL结尾。程序员应通过GetStringLength()
或GetStringUTFLength()
确定缓冲区容量要求。
NewString
jstring NewString(JNIEnv *env, const jchar *unicodeChars, jsize len);
从Unicode字符数组构造一个新的java.lang.String
对象。
链接:
JNIEnv接口函数表中的索引163。
参数:
env
: JNI接口指针,不得为NULL
。
unicodeChars
: 指向Unicode字符串的指针。可以是NULL
值,此时len
必须为0。
len
: Unicode字符串的长度。可以为0。
返回:
返回一个Java字符串对象,如果无法构造字符串则返回NULL
。
抛出:
OutOfMemoryError
: 如果系统内存耗尽。
GetStringLength
jsize GetStringLength(JNIEnv *env, jstring string);
返回Java字符串的长度(Unicode字符数)。
链接:
JNIEnv接口函数表中的索引164。
参数:
env
: JNI接口指针,不得为NULL
。
string
: Java字符串对象,不得为NULL
。
返回:
返回Java字符串的长度。
GetStringChars
const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);
返回字符串的Unicode字符数组的指针。此指针有效直到调用ReleaseStringChars()
。
如果isCopy
不是NULL
,则如果进行了复制,则将*isCopy
设置为JNI_TRUE
; 如果没有进行复制,则将其设置为JNI_FALSE
。
链接:
JNIEnv接口函数表中的索引165。
参数:
env
: JNI接口指针,不得为NULL
。
string
: Java字符串对象,不得为NULL
。
isCopy
: 指向布尔值的指针,可以是NULL
值。
返回:
返回指向Unicode字符串的指针,如果操作失败则返回NULL
。
ReleaseStringChars
void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);
通知VM本地代码不再需要访问chars
。 chars
参数是从string
使用GetStringChars()
获得的指针。
链接:
JNIEnv接口函数表中的索引166。
参数:
env
: JNI接口指针,不得为NULL
。
string
: Java字符串对象,不得为NULL
。
chars
: 指向Unicode字符串的指针,如先前由GetStringChars()
返回。
NewStringUTF
jstring NewStringUTF(JNIEnv *env, const char *bytes);
从修改后的UTF-8编码字符数组构造一个新的java.lang.String
对象。
链接:
JNIEnv接口函数表中的索引167。
参数:
env
: JNI接口指针,不得为NULL
。
bytes
: 指向修改后的UTF-8字符串的指针,不得为NULL
。
返回:
返回一个Java字符串对象,如果无法构造字符串则返回NULL
。
抛出:
OutOfMemoryError
: 如果系统内存耗尽。
GetStringUTFLength
jsize GetStringUTFLength(JNIEnv *env, jstring string);
返回字符串的修改后的UTF-8表示的字节长度。
链接:
JNIEnv接口函数表中的索引168。
参数:
env
: JNI接口指针,不得为NULL
。
string
: Java字符串对象,不得为NULL
。
返回:
返回字符串的UTF-8长度。
GetStringUTFChars
const char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);
返回一个指向以修改后的UTF-8编码表示的字符串的字节数组的指针。该数组有效直到被ReleaseStringUTFChars()
释放。
如果isCopy
不是NULL
,则如果进行了复制,则将*isCopy
设置为JNI_TRUE
;如果没有进行复制,则设置为JNI_FALSE
。
链接:
在JNIEnv接口函数表中的索引169。
参数:
env
: JNI接口指针,不得为NULL
。
string
: Java字符串对象,不得为NULL
。
isCopy
: 指向布尔值的指针,可以是NULL
值。
返回:
返回一个指向修改后的UTF-8字符串的指针,如果操作失败则返回NULL
。
ReleaseStringUTFChars
void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);
通知虚拟机本地代码不再需要访问utf
。 utf
参数是使用GetStringUTFChars()
从string
派生的指针。
链接:
在JNIEnv接口函数表中的索引170。
参数:
env
: JNI接口指针,不得为NULL
。
string
: Java字符串对象,不得为NULL
。
utf
: 指向修改后的UTF-8字符串的指针,先前由GetStringUTFChars()
返回。
注意:在JDK/JRE 1.1中,程序员可以在用户提供的缓冲区中获取原始数组元素。从JDK/JRE 1.2开始,提供了一组额外的函数,允许本地代码在用户提供的缓冲区中获取Unicode(UTF-16)或修改后的UTF-8编码的字符。请参阅下面的函数。
GetStringRegion
void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
将从偏移量start
开始的len
个Unicode字符复制到给定的缓冲区buf
中。
链接:
在JNIEnv接口函数表中的索引220。
参数:
env
: JNI接口指针,不得为NULL
。
str
: Java字符串对象,不得为NULL
。
start
: 要复制的字符串中第一个Unicode字符的索引。必须大于或等于零,并且小于字符串长度("GetStringLength()
")。
len
: 要复制的Unicode字符数。必须大于或等于零,并且"start + len
"必须小于字符串长度("GetStringLength()
")。
buf
: 要将字符串区域复制到的Unicode字符缓冲区。如果给定len
大于0,则不得为NULL
。
抛出:
StringIndexOutOfBoundsException
:索引溢出时。
自:
JDK/JRE 1.2
GetStringUTFRegion
void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);
将从偏移量start
开始的len
个Unicode字符转换为修改后的UTF-8编码,并将结果放入给定的缓冲区buf
中。
len
参数指定Unicode字符的数量。生成的修改后的UTF-8编码字符数可能大于给定的len
参数。可以使用GetStringUTFLength()
来确定所需字符缓冲区的最大大小。
由于此规范不要求生成的字符串副本以NULL结尾,建议在使用此函数之前清除给定的字符缓冲区(例如"memset()
"),以便安全地执行strlen()
。
链接:
在JNIEnv接口函数表中的索引221。
参数:
env
: JNI接口指针,不得为NULL
。
str
: Java字符串对象,不得为NULL
。
start
: 要复制的字符串中第一个Unicode字符的索引。必须大于或等于零,并且小于字符串长度。
len
: 要复制的Unicode字符数。必须大于零,并且"start + len
"必须小于字符串长度("GetStringLength()
")。
buf
: 要将字符串区域复制到的Unicode字符缓冲区。如果给定len
大于0,则不得为NULL
。
抛出:
StringIndexOutOfBoundsException
:索引溢出时。
自:
JDK/JRE 1.2
GetStringCritical, ReleaseStringCritical
const jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);
这两个函数的语义类似于现有的Get/ReleaseStringChars
函数。如果可能,虚拟机将返回字符串元素的指针;否则将进行复制。但是,对于这些函数的使用有重要限制。在由Get/ReleaseStringCritical
调用包围的代码段中,本地代码不得发出任意JNI调用,或导致当前线程阻塞。
Get/ReleaseStringCritical
的限制类似于Get/ReleasePrimitiveArrayCritical
的限制。
链接(GetStringCritical):
在JNIEnv接口函数表中的索引224。
链接(ReleaseStingCritical):
在JNIEnv接口函数表中的索引225。
另请参阅:
自:
JDK/JRE 1.2
数组操作
GetArrayLength
jsize GetArrayLength(JNIEnv *env, jarray array);
返回数组中的元素数量。
链接:
在JNIEnv接口函数表中的索引171。
参数:
env
: JNI接口指针,不得为NULL
。
array
: Java数组对象,不得为NULL
。
返回:
返回数组的长度。
NewObjectArray
jobjectArray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);
构造一个持有elementClass
类中对象的新数组。所有元素最初设置为initialElement
。
链接:
在JNIEnv接口函数表中的索引172。
参数:
env
: JNI接口指针,不得为NULL
。
length
: 数组大小,必须为>= 0。
elementClass
: 数组元素类,不得为NULL
。
initialElement
: 初始化值,可以是NULL
值。
返回:
返回一个Java数组对象,如果无法构造数组则返回NULL
。
抛出:
OutOfMemoryError
:如果系统内存耗尽。
GetObjectArrayElement
jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);
返回Object
数组的一个元素。
链接:
在JNIEnv接口函数表中的索引173。
参数:
env
: JNI接口指针,不得为NULL
。
array
: Java数组,不得为NULL
。
index
: 数组索引,必须为>= 0且小于数组长度("GetArrayLength()
")。
返回:
返回一个Java对象。
抛出:
ArrayIndexOutOfBoundsException
:如果index
未指定数组中的有效索引。
SetObjectArrayElement
void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value);
设置Object
数组的一个元素。
链接:
在JNIEnv接口函数表中的索引174。
参数:
env
: JNI接口指针,不得为NULL
。
array
: Java数组,不得为NULL
。
index
: 数组索引,必须为>= 0且小于数组长度("GetArrayLength()
")。
value
: 新值,可以是NULL
值。
抛出:
ArrayIndexOutOfBoundsException
:如果index
未指定数组中的有效索引。
ArrayStoreException
:如果value
的类不是数组的元素类的子类。
New<PrimitiveType>Array Routines
ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);
用于构造新的原始数组对象的一组操作。以下表格描述了特定原始数组构造函数。您应该从此表中选择一个实际的原始数组构造函数例程名称替换New<PrimitiveType>Array,并用该例程的相应数组类型替换ArrayType。
New<PrimitiveType>Array例程 | 数组类型 |
---|---|
NewBooleanArray() |
jbooleanArray |
NewByteArray() |
jbyteArray |
NewCharArray() |
jcharArray |
NewShortArray() |
jshortArray |
NewIntArray() |
jintArray |
NewLongArray() |
jlongArray |
NewFloatArray() |
jfloatArray |
NewDoubleArray() |
jdoubleArray |
链接:
JNIEnv接口函数表中的索引。
New<PrimitiveType>Array例程 | 索引 |
---|---|
NewBooleanArray() |
175 |
NewByteArray() |
176 |
NewCharArray() |
177 |
NewShortArray() |
178 |
NewIntArray() |
179 |
NewLongArray() |
180 |
NewFloatArray() |
181 |
NewDoubleArray() |
182 |
参数:
env
: JNI接口指针,不得为NULL
。
length
: 数组长度,必须大于等于0。
返回:
返回一个Java数组,如果无法构造数组则返回NULL
。
抛出:
OutOfMemoryError
: 如果系统内存耗尽。
获取<PrimitiveType>ArrayElements例程
NativeType *
Get<PrimitiveType>ArrayElements(JNIEnv *env,
ArrayType array, jboolean *isCopy);
一系列函数,返回原始数组的内容。结果在对应的Release<PrimitiveType>ArrayElements()函数被调用之前有效。由于返回的数组可能是Java数组的副本,对返回的数组进行的更改不一定会反映在原始数组中,直到调用Release<PrimitiveType>ArrayElements()为止。
如果isCopy
不是NULL
,则如果进行了复制,则将*isCopy
设置为JNI_TRUE
;如果没有进行复制,则设置为JNI_FALSE
。
以下表格描述了特定原始数组元素访问器。您应进行以下替换:
- 将Get<PrimitiveType>ArrayElements替换为以下表格中实际的原始元素访问器例程名称之一。
- 将ArrayType替换为相应的数组类型。
- 将NativeType替换为该例程的相应本机类型。
无论布尔数组在Java虚拟机中如何表示,GetBooleanArrayElements()
始终返回指向jbooleans
的指针,每个字节表示一个元素(未打包的表示)。所有其他类型的数组都保证在内存中是连续的。
Get<PrimitiveType>ArrayElements例程 | 数组类型 | 本机类型 |
---|---|---|
GetBooleanArrayElements() |
jbooleanArray | jboolean |
GetByteArrayElements() |
jbyteArray | jbyte |
GetCharArrayElements() |
jcharArray | jchar |
GetShortArrayElements() |
jshortArray | jshort |
GetIntArrayElements() |
jintArray | jint |
GetLongArrayElements() |
jlongArray | jlong |
GetFloatArrayElements() |
jfloatArray | jfloat |
GetDoubleArrayElements() |
jdoubleArray | jdouble |
链接:
JNIEnv接口函数表中的索引。
Get<PrimitiveType>ArrayElements例程 | 索引 |
---|---|
GetBooleanArrayElements() |
183 |
GetByteArrayElements() |
184 |
GetCharArrayElements() |
185 |
GetShortArrayElements() |
186 |
GetIntArrayElements() |
187 |
GetLongArrayElements() |
188 |
GetFloatArrayElements() |
189 |
GetDoubleArrayElements() |
190 |
参数:
env
: JNI接口指针,不得为NULL
。
array
: Java数组对象,不得为NULL
。
isCopy
: 指向布尔值的指针,可以是NULL
值。
返回:
返回指向数组元素的指针,如果操作失败则返回NULL
。
抛出:
OutOfMemoryError
: 如果系统内存耗尽。
释放<PrimitiveType>ArrayElements例程
void
Release<PrimitiveType>ArrayElements(JNIEnv *env,
ArrayType array,
NativeType *elems, jint mode);
一系列函数,通知虚拟机本机代码不再需要访问elems
。 elems
参数是使用相应的Get<PrimitiveType>ArrayElements()函数从array
派生的指针。必要时,此函数将所有对elems
进行的更改复制回原始数组。
mode
参数提供有关如何释放数组缓冲区的信息。如果elems
不是数组中元素的副本,则mode
不起作用。否则,mode
具有以下影响,如下表所示:
模式 | 操作 |
---|---|
0 |
复制回内容并释放elems 缓冲区 |
JNI_COMMIT |
复制回内容但不释放elems 缓冲区 |
JNI_ABORT |
释放缓冲区而不复制回可能的更改 |
在大多数情况下,程序员将"0"作为mode
参数传递,以确保对固定和复制数组的行为一致。其他选项可以让程序员更加控制内存管理,但应极度小心使用。如果在elems
是array
中元素的副本时,将JNI_COMMIT
作为mode
参数传递,则应该进行最终调用,调用Release<PrimitiveType>ArrayElements并传递一个"0"或JNI_ABORT
的mode
参数,以释放elems
缓冲区。
下表描述了组成原始数组释放器系列的具体例程。您应进行以下替换:
- 用以下表中实际的原始数组释放器例程名称之一替换Release<PrimitiveType>ArrayElements。
- 用相应的数组类型替换ArrayType。
- 用该例程的相应本机类型替换NativeType。
Release<PrimitiveType>ArrayElements 例程 | 数组类型 | 本机类型 |
---|---|---|
ReleaseBooleanArrayElements() |
jbooleanArray | jboolean |
ReleaseByteArrayElements() |
jbyteArray | jbyte |
ReleaseCharArrayElements() |
jcharArray | jchar |
ReleaseShortArrayElements() |
jshortArray | jshort |
ReleaseIntArrayElements() |
jintArray | jint |
ReleaseLongArrayElements() |
jlongArray | jlong |
ReleaseFloatArrayElements() |
jfloatArray | jfloat |
ReleaseDoubleArrayElements() |
jdoubleArray | jdouble |
链接:
JNIEnv接口函数表中的索引。
Release<PrimitiveType>ArrayElements 例程 | 索引 |
---|---|
ReleaseBooleanArrayElements() |
191 |
ReleaseByteArrayElements() |
192 |
ReleaseCharArrayElements() |
193 |
ReleaseShortArrayElements() |
194 |
ReleaseIntArrayElements() |
195 |
ReleaseLongArrayElements() |
196 |
ReleaseFloatArrayElements() |
197 |
ReleaseDoubleArrayElements() |
198 |
参数:
env
:JNI接口指针,不得为NULL
。
array
:Java数组对象,不得为NULL
。
elems
:数组元素的指针,由先前的Get<PrimitiveType>ArrayElements调用返回。
mode
:释放模式:0
、JNI_COMMIT
或JNI_ABORT
。
Get<PrimitiveType>ArrayRegion 例程
void
Get<PrimitiveType>ArrayRegion(JNIEnv *env,
ArrayType array, jsize start, jsize len,
NativeType *buf);
一组函数,将原始数组的区域复制到缓冲区中。
以下表描述了特定的原始数组元素访问器。您应进行以下替换:
- 用以下表中实际的原始元素访问器例程名称之一替换Get<PrimitiveType>ArrayRegion。
- 用相应的数组类型替换ArrayType。
- 用该例程的相应本机类型替换NativeType。
Get<PrimitiveType>ArrayRegion 例程 | 数组类型 | 本机类型 |
---|---|---|
GetBooleanArrayRegion() |
jbooleanArray | jboolean |
GetByteArrayRegion() |
jbyteArray | jbyte |
GetCharArrayRegion() |
jcharArray | jchar |
GetShortArrayRegion() |
jshortArray | jshort |
GetIntArrayRegion() |
jintArray | jint |
GetLongArrayRegion() |
jlongArray | jlong |
GetFloatArrayRegion() |
jfloatArray | jfloat |
GetDoubleArrayRegion() |
jdoubleArray | jdouble |
链接:
JNIEnv接口函数表中的索引。
Get<PrimitiveType>ArrayRegion 例程 | 索引 |
---|---|
GetBooleanArrayRegion() |
199 |
GetByteArrayRegion() |
200 |
GetCharArrayRegion() |
201 |
GetShortArrayRegion() |
202 |
GetIntArrayRegion() |
203 |
GetLongArrayRegion() |
204 |
GetFloatArrayRegion() |
205 |
GetDoubleArrayRegion() |
206 |
参数:
env
:JNI接口指针,不得为NULL
。
array
:Java数组,不得为NULL
。
start
:起始索引,必须大于或等于零,并且小于数组长度(GetArrayLength()
)。
len
:要复制的元素数量,必须大于或等于零,并且"start + len
"必须小于数组长度("GetArrayLength()
")。
buf
:目标缓冲区,不得为NULL
。
抛出:
ArrayIndexOutOfBoundsException
:如果区域中的一个索引无效。
Set<PrimitiveType>ArrayRegion 例程
void
Set<PrimitiveType>ArrayRegion(JNIEnv *env,
ArrayType array, jsize start, jsize len, const
NativeType *buf);
一组函数,从缓冲区中将原始数组的区域复制回去。
以下表描述了特定的原始数组元素访问器。您应进行以下替换:
- 用以下表中的实际原始元素访问例程名称之一替换Set<PrimitiveType>ArrayRegion。
- 用相应的数组类型替换ArrayType。
- 用相应的例程的本机类型替换NativeType。
Set<PrimitiveType>ArrayRegion 例程 | 数组类型 | 本机类型 |
---|---|---|
SetBooleanArrayRegion() |
jbooleanArray | jboolean |
SetByteArrayRegion() |
jbyteArray | jbyte |
SetCharArrayRegion() |
jcharArray | jchar |
SetShortArrayRegion() |
jshortArray | jshort |
SetIntArrayRegion() |
jintArray | jint |
SetLongArrayRegion() |
jlongArray | jlong |
SetFloatArrayRegion() |
jfloatArray | jfloat |
SetDoubleArrayRegion() |
jdoubleArray | jdouble |
链接:
JNIEnv接口函数表中的索引。
Set<PrimitiveType>ArrayRegion 例程 | 索引 |
---|---|
SetBooleanArrayRegion() |
207 |
SetByteArrayRegion() |
208 |
SetCharArrayRegion() |
209 |
SetShortArrayRegion() |
210 |
SetIntArrayRegion() |
211 |
SetLongArrayRegion() |
212 |
SetFloatArrayRegion() |
213 |
SetDoubleArrayRegion() |
214 |
参数:
env
:JNI接口指针,不得为NULL
。
array
:Java数组,不得为NULL
。
start
:起始索引,必须大于或等于零,并且小于数组长度(GetArrayLength()
)。
len
:要复制的元素数量,必须大于或等于零,并且"start + len
"必须小于数组长度("GetArrayLength()
")。
buf
:源缓冲区,不得为NULL
。
抛出:
ArrayIndexOutOfBoundsException
:如果区域中的一个索引无效。
注意:程序员可以使用Get/Release<primitivetype>ArrayElements函数来获取原始数组元素的指针。如果VM支持固定,将返回指向原始数据的指针;否则将进行复制。Get/Release<primitivetype>ArrayCritical函数允许本机代码获取数组元素的直接指针,即使VM不支持固定。
GetPrimitiveArrayCritical, ReleasePrimitiveArrayCritical
void * GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy);
void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode);
这两个函数的语义与现有的Get/Release<primitivetype>ArrayElements函数非常相似。如果可能,VM将返回指向原始数组的指针;否则将进行复制。但是,这些函数的使用方式有重要限制。
在调用GetPrimitiveArrayCritical
之后,本机代码在调用ReleasePrimitiveArrayCritical
之前不应长时间运行。我们必须将这对函数内部的代码视为在“关键区域”中运行。在关键区域内,本机代码不得调用其他JNI函数,或者可能导致当前线程阻塞并等待另一个Java线程的任何系统调用。(例如,当前线程不得在另一个Java线程正在写入的流上调用read
。)
这些限制使得本机代码更有可能获得未复制的数组版本,即使VM不支持固定。例如,当本机代码持有通过GetPrimitiveArrayCritical
获取的数组指针时,VM可能会暂时禁用垃圾回收。
可以嵌套多对GetPrimtiveArrayCritical
和ReleasePrimitiveArrayCritical
。例如:
jint len = (*env)->GetArrayLength(env, arr1);
jbyte *a1 = (*env)->GetPrimitiveArrayCritical(env, arr1, 0);
jbyte *a2 = (*env)->GetPrimitiveArrayCritical(env, arr2, 0);
/* 我们需要检查以防VM尝试进行复制。 */
if (a1 == NULL || a2 == NULL) {
... /* 抛出内存不足异常 */
}
memcpy(a1, a2, len);
(*env)->ReleasePrimitiveArrayCritical(env, arr2, a2, 0);
(*env)->ReleasePrimitiveArrayCritical(env, arr1, a1, 0);
请注意,GetPrimitiveArrayCritical
如果VM在内部以不同格式表示数组,仍可能会复制数组。因此,我们需要将其返回值与NULL
进行检查,以防可能的内存不足情况。
GetPrimitiveArrayCritical
链接:
JNIEnv接口函数表中的索引222。
参数:
env
:JNI接口指针,不得为NULL
。
array
:Java数组,不得为NULL
。
isCopy
:指向布尔值的指针,可以是NULL
值。
返回:
返回数组元素的指针,如果操作失败则返回NULL。
抛出:
OutOfMemoryError
:如果系统内存不足。
自JDK/JRE 1.2起
ReleasePrimitiveArrayCritical
链接:
JNIEnv接口函数表中的索引223。
参数:
env
:JNI接口指针,不得为NULL
。
array
:Java数组,不得为NULL
。
carray
:由GetPrimitiveArrayCritical
返回的关键数组指针。
mode
:释放模式(参见原始数组释放模式):0
、JNI_COMMIT
或JNI_ABORT
。如果carray
不是副本,则忽略。
自JDK/JRE 1.2起
注册本机方法
RegisterNatives
jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods);
使用clazz
参数指定的类注册本机方法。 methods
参数指定包含本机方法的名称、签名和函数指针的JNINativeMethod
结构数组。 JNINativeMethod
结构的name
和signature
字段是指向修改后的UTF-8字符串的指针。 nMethods
参数指定数组中的本机方法数量。 JNINativeMethod
结构定义如下:
typedef struct {
char *name;
char *signature;
void *fnPtr;
} JNINativeMethod;
函数指针名义上必须具有以下签名:
ReturnType (*fnPtr)(JNIEnv *env, jobject objectOrClass, ...);
请注意,RegisterNatives
可以通过更改要为给定本机Java方法执行的本机代码来更改JVM的文档化行为(包括加密算法、正确性、安全性、类型安全性)。因此,谨慎使用使用具有RegisterNatives
函数的本机库的应用程序。
链接:
JNIEnv接口函数表中的索引215。
参数:
env
:JNI接口指针,不得为NULL
。
clazz
:Java类对象,不得为NULL
。
methods
:类中的本机方法,不得为NULL
。
nMethods
:类中的本机方法数量,必须大于零。
返回:
成功返回“0”;失败返回负值。
抛出:
NoSuchMethodError
:如果找不到指定的方法或方法不是本机方法。
UnregisterNatives
jint UnregisterNatives(JNIEnv *env, jclass clazz);
取消注册类的本机方法。 类返回到链接或注册其本机方法函数之前的状态。
此函数不应在正常本机代码中使用。相反,它为特殊程序提供了重新加载和重新链接本机库的方法。
链接:
在JNIEnv接口函数表中的索引为216。
参数:
env
:JNI接口指针,不得为NULL
。
clazz
:一个Java类对象,不得为NULL
。
返回值:
成功时返回“0”;失败时返回负值。
监视器操作
MonitorEnter
jint MonitorEnter(JNIEnv *env, jobject obj);
进入与obj
引用的底层Java对象关联的监视器。
进入与obj
引用的对象关联的监视器。obj
引用不得为NULL
。
每个Java对象都有一个与之关联的监视器。如果当前线程已经拥有与obj
关联的监视器,则会增加监视器中的计数器,指示该线程进入监视器的次数。如果与obj
关联的监视器没有被任何线程拥有,则当前线程将成为监视器的所有者,将该监视器的进入计数设置为1。如果另一个线程已经拥有与obj
关联的监视器,则当前线程将等待直到监视器被释放,然后再次尝试获取所有权。
通过MonitorEnter
JNI函数调用进入的监视器不能使用monitorexit
Java虚拟机指令或同步方法返回退出。MonitorEnter
JNI函数调用和monitorenter
Java虚拟机指令可能会竞争进入与同一对象关联的监视器。
为避免死锁,通过MonitorEnter
JNI函数调用进入的监视器必须使用MonitorExit
JNI调用退出,除非使用DetachCurrentThread
调用隐式释放JNI监视器。
链接:
在JNIEnv接口函数表中的索引为217。
参数:
env
:JNI接口指针,不得为NULL
。
obj
:一个普通的Java对象或类对象,不得为NULL
。
返回值:
成功时返回“0”;失败时返回负值。
MonitorExit
jint MonitorExit(JNIEnv *env, jobject obj);
当前线程必须是与obj
引用的底层Java对象关联的监视器的所有者。线程减少指示它进入此监视器的次数。如果计数器的值变为零,则当前线程释放监视器。
本机代码不能使用MonitorExit
退出通过同步方法或monitorenter
Java虚拟机指令进入的监视器。
链接:
在JNIEnv接口函数表中的索引为218。
参数:
env
:JNI接口指针,不得为NULL
。
obj
:一个普通的Java对象或类对象,不得为NULL
。
返回值:
成功时返回“0”;失败时返回负值。
抛出:
IllegalMonitorStateException
:如果当前线程不拥有监视器。
NIO支持
NIO相关的入口点允许本机代码访问java.nio
的直接缓冲区。直接缓冲区的内容可能驻留在普通垃圾收集堆之外的本机内存中。有关直接缓冲区的信息,请参阅NIO包中的缓冲区和java.nio.ByteBuffer
类的规范。
三个函数允许JNI代码创建、检查和操作直接缓冲区:
每个Java虚拟机的实现必须支持这些函数,但并非每个实现都必须支持对直接缓冲区的JNI访问。如果JVM不支持这种访问,则NewDirectByteBuffer
和GetDirectBufferAddress
函数必须始终返回NULL
,而GetDirectBufferCapacity
函数必须始终返回-1
。如果JVM支持这种访问,则这三个函数必须实现为返回适当的值。
NewDirectByteBuffer
jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity);
分配并返回一个直接引用内存地址为address
、长度为capacity
字节的java.nio.ByteBuffer
。返回的缓冲区的字节顺序始终为大端序(高字节优先;java.nio.ByteOrder.BIG_ENDIAN
)。
调用此函数的本机代码并将结果字节缓冲区对象返回给Java级别代码时,应确保缓冲区引用的是一个可供读取和(如果适用)写入的有效内存区域。尝试从Java代码访问无效内存位置将返回任意值、没有可见效果,或引发未指定的异常。
链接:
在JNIEnv接口函数表中的索引为229。
参数:
env
:JNI接口指针,不得为NULL
。
address
:内存区域的起始地址,不得为NULL
。
capacity
:内存区域的字节大小,必须为非负且小于或等于Integer.MAX_VALUE
返回值:
返回新实例化的java.nio.ByteBuffer
对象的本地引用。如果发生异常,或者此虚拟机不支持对直接缓冲区的JNI访问,则返回NULL
。
抛出:
IllegalArgumentException
:如果capacity
为负数或大于Integer.MAX_VALUE
OutOfMemoryError
:如果分配ByteBuffer
对象失败
自:
JDK/JRE 1.4
GetDirectBufferAddress
void* GetDirectBufferAddress(JNIEnv* env, jobject buf);
获取并返回给定直接java.nio.Buffer
引用的内存区域的起始地址。
此函数允许本机代码访问与Java代码通过缓冲区对象访问的相同内存区域。
链接:
在JNIEnv接口函数表中的索引为230。
参数:
env
:JNI接口指针,不得为NULL
。
buf
:一个直接java.nio.Buffer
对象,不得为NULL
。
返回值:
返回缓冲区引用的内存区域的起始地址。如果内存区域未定义,给定对象不是直接java.nio.Buffer
,或者此虚拟机不支持对直接缓冲区的JNI访问,则返回NULL
。
自:
JDK/JRE 1.4
GetDirectBufferCapacity
jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf);
获取并返回给定直接java.nio.Buffer
引用的内存区域的容量。容量是内存区域包含的元素数量。
链接:
在JNIEnv接口函数表中的索引为231。
参数:
env
:JNI接口指针,不得为NULL
。
buf
:一个直接java.nio.Buffer
对象,不得为NULL
。
返回值:
返回与缓冲区关联的内存区域的容量。如果给定对象不是直接java.nio.Buffer
,对象是非对齐视图缓冲区且处理器架构不支持非对齐访问,或者此虚拟机不支持对直接缓冲区的JNI访问,则返回-1
。
自:
JDK/JRE 1.4
反射支持
程序员可以使用JNI调用Java方法或访问Java字段,如果他们知道方法或字段的名称和类型。Java核心反射API允许程序员在运行时审查Java类。JNI提供了一组在JNI中使用的字段和方法ID与Java核心反射API中使用的字段和方法对象之间进行转换的函数。
FromReflectedMethod
jmethodID FromReflectedMethod(JNIEnv *env, jobject method);
将java.lang.reflect.Method
或java.lang.reflect.Constructor
对象转换为方法ID。
链接:
在JNIEnv接口函数表中的索引为7。
参数:
env
:JNI接口指针,不得为NULL
。
method
:一个java.lang.reflect.Method
或java.lang.reflect.Constructor
对象,不得为NULL
。
返回值:
与给定的Java反射方法对应的JNI方法ID,如果操作失败则返回NULL。
自:
JDK/JRE 1.2
FromReflectedField
jfieldID FromReflectedField(JNIEnv *env, jobject field);
将java.lang.reflect.Field
转换为字段ID。
链接:
在JNIEnv接口函数表中的索引为8。
参数:
env
:JNI接口指针,不得为NULL
。
field
:一个java.lang.reflect.Field
对象,不得为NULL
。
返回值:
与给定的Java反射field
对应的JNI字段ID,如果操作失败则返回NULL
。
自:
JDK/JRE 1.2
ToReflectedMethod
jobject ToReflectedMethod(JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic);
将从cls
派生的方法ID转换为java.lang.reflect.Method
或java.lang.reflect.Constructor
对象。isStatic
必须设置为JNI_TRUE
,如果方法ID引用静态字段,则设置为JNI_FALSE
。
如果失败,则抛出OutOfMemoryError
并返回0。
链接:
在JNIEnv接口函数表中的索引为9。
参数:
env
:JNI接口指针,不得为NULL
。
cls
:一个Java类对象,不得为NULL
。
methodID
:一个方法ID,不得为NULL
。
isStatic
:表示给定的methodID
是否为静态方法。
返回值:
返回与给定的methodID
对应的java.lang.reflect.Method
或java.lang.reflect.Constructor
的实例,如果操作失败则返回NULL
。
自:JDK/JRE 1.2
ToReflectedField
jobject ToReflectedField(JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic);
将从cls
派生的字段ID转换为一个java.lang.reflect.Field
对象。isStatic
必须设置为JNI_TRUE
,如果fieldID
指的是一个静态字段,则设置为JNI_FALSE
。
如果失败则抛出OutOfMemoryError
并返回0。
链接:
在JNIEnv接口函数表中的索引12。
参数:
env
:JNI接口指针,不得为NULL
。
cls
:Java类对象,不得为NULL
。
fieldID
:字段ID,不得为NULL
。
isStatic
:表示给定的fieldID
是否为静态字段。
返回:
返回与给定的fieldID
对应的java.lang.reflect.Field
的实例,如果操作失败则返回NULL
。
自:JDK/JRE 1.2
Java VM接口
GetJavaVM
jint GetJavaVM(JNIEnv *env, JavaVM **vm);
返回与当前线程关联的Java VM接口(在调用API中使用)。结果放置在第二个参数vm
指向的位置。
链接:
在JNIEnv接口函数表中的索引219。
参数:
env
:JNI接口指针,不得为NULL
。
vm
:结果应放置的指针,不得为NULL
。
返回:
成功返回"0";失败返回负值。