第四章:JNI函数

本章作为JNI函数的参考部分。它提供了所有JNI函数的完整列表。它还展示了JNI函数表的确切布局。

请注意使用术语“必须”来描述对JNI程序员的限制。例如,当您看到某个JNI函数必须接收一个非NULL对象时,您有责任确保不会将NULL传递给该JNI函数。因此,JNI实现不需要在该JNI函数中执行NULL指针检查。在明确不允许的情况下传递NULL可能导致意外异常或致命崩溃。

定义可能同时返回NULL并在错误时抛出异常的函数,可以选择仅返回NULL以指示错误,但不抛出任何异常。例如,JNI实现可能认为“内存不足”条件是临时的,并且可能不希望抛出OutOfMemoryError,因为这看起来是致命的(JDK API java.lang.Error文档:“指示严重问题,合理的应用程序不应尝试捕获”)。

本章的部分内容改编自Netscape的JRI文档。

参考资料根据其用途将函数分组。参考部分按以下功能区域组织:


接口函数表

每个函数通过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,则类加载器确定如下:

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


模块操作


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的情况包括:


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_ERRJNI_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的情况包括:

自版本:

JDK/JRE 1.2


弱全局引用

弱全局引用是一种特殊类型的全局引用。 与普通全局引用不同,弱全局引用允许底层Java对象被垃圾回收。 弱全局引用可以在任何需要全局或局部引用的情况下使用。

弱全局引用与Java虚拟引用(java.lang.ref.PhantomReference)相关。 对特定对象的弱全局引用在确定对象是否虚引用可达(请参阅java.lang.ref)时被视为引用该对象的虚引用。 当垃圾回收器清除引用同一对象的PhantomReference时,这样的弱全局引用将在同一时间变得等效于NULL

由于垃圾回收可能在本机方法运行时发生,因此由弱全局引用引用的对象可以随时被释放。 虽然弱全局引用可以在需要全局引用的地方使用,但通常不适合这样做,因为它们可能在没有通知的情况下变得等效于NULL

IsSameObject可用于比较弱全局引用与非NULL局部或全局引用。 如果对象相同,则只要另一个引用未被删除,弱全局引用就不会变得等效于NULL

IsSameObject还可用于将弱全局引用与NULL进行比较,以确定底层对象是否已被释放。 但是,程序员不应依赖此检查来确定将来的JNI函数调用中是否可以使用弱全局引用(作为非NULL引用),因为介入的垃圾回收可能会更改弱全局引用。

相反,建议使用JNI函数NewLocalRefNewGlobalRef获取对底层对象的(强)局部或全局引用。 如果对象已被释放,这些函数将返回NULL。 否则,新引用将防止底层对象被释放。 如果新引用非NULL,则可以用于访问底层对象,并在不再需要此访问时删除。


NewWeakGlobalRef

jweak NewWeakGlobalRef(JNIEnv *env, jobject obj);

创建一个新的弱全局引用。 弱全局引用不会阻止给定对象的垃圾回收。 可以使用IsSameObject来测试引用的对象是否已被释放。 如果obj引用为null,或者obj是弱全局引用,或者虚拟机内存不足,则返回NULL。 如果虚拟机内存不足,将抛出OutOfMemoryError

链接:

在JNIEnv接口函数表中的索引为226。

参数:

env:JNI接口指针,不得为NULL

obj:要为其创建全局弱引用的对象。

返回:

返回给定obj的全局弱引用。

如果发生以下情况可能返回NULL

抛出:

如果系统内存耗尽,则抛出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_listargs参数中,紧随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_FALSENULL对象可以转换为任何类。


IsSameObject

jboolean IsSameObject(JNIEnv *env, jobject ref1, jobject ref2);

测试两个引用是否指向相同的Java对象。

链接:

在JNIEnv接口函数表中的索引24。

参数:

env:JNI接口指针,不得为NULL

ref1:Java对象,可能为NULL

ref2:Java对象,可能为NULL

返回:

如果ref1ref2指向相同的Java对象,或者两者都为NULL,则返回JNI_TRUE;否则返回JNI_FALSE


访问对象的字段


GetFieldID

jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);

返回类的实例(非静态)字段的字段ID。字段由其名称和签名指定。Get<type>FieldSet<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 访问器例程系列
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 访问器例程系列
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 访问器例程系列
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 访问器例程系列
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>作为方法名称并将voidV)作为返回类型。

链接:

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_listargs参数中,该参数紧随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_listargs参数中,该参数紧随methodID参数。 CallNonvirtualMethodV例程接受这些参数,并将它们传递给程序员希望调用的Java方法。

以下表格根据它们的结果类型描述了每个方法调用例程。您应该在CallNonvirtual<type>Method中用方法的Java类型替换type,或使用表中的实际方法调用例程名称之一,并用相应的本机类型替换NativeType

CallNonvirtual<type>Method例程
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例程
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>FieldSetStatic<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访问器例程系列
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 访问器例程系列
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 访问器例程系列
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 访问器例程系列
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_listargs参数中,该参数紧随methodID参数。 CallStaticMethodV例程接受这些参数,并依次将它们传递给程序员希望调用的Java方法。

以下表格根据它们的结果类型描述了每个方法调用例程。您应该将CallStatic<type>Method中的type替换为方法的Java类型,或者从表中选择一个实际的方法调用例程名称,并将NativeType替换为该例程的相应本机类型。

CallStatic<type>Method 调用例程
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 调用例程
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字符串做出假设。从这些操作返回的字符串:

因此不需要以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本地代码不再需要访问charschars参数是从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);

通知虚拟机本地代码不再需要访问utfutf参数是使用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。

另请参阅:

GetStringChars

ReleaseStringChars

自:

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数组构造函数系列
New<PrimitiveType>Array例程 数组类型
NewBooleanArray() jbooleanArray
NewByteArray() jbyteArray
NewCharArray() jcharArray
NewShortArray() jshortArray
NewIntArray() jintArray
NewLongArray() jlongArray
NewFloatArray() jfloatArray
NewDoubleArray() jdoubleArray

链接:

JNIEnv接口函数表中的索引。

New<PrimitiveType>Array数组构造函数系列
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

以下表格描述了特定原始数组元素访问器。您应进行以下替换:

无论布尔数组在Java虚拟机中如何表示,GetBooleanArrayElements()始终返回指向jbooleans的指针,每个字节表示一个元素(未打包的表示)。所有其他类型的数组都保证在内存中是连续的。

Get<PrimitiveType>ArrayElements访问器例程系列
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访问器例程系列
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);

一系列函数,通知虚拟机本机代码不再需要访问elemselems参数是使用相应的Get<PrimitiveType>ArrayElements()函数从array派生的指针。必要时,此函数将所有对elems进行的更改复制回原始数组。

mode参数提供有关如何释放数组缓冲区的信息。如果elems不是数组中元素的副本,则mode不起作用。否则,mode具有以下影响,如下表所示:

原始数组释放模式
模式 操作
0 复制回内容并释放elems缓冲区
JNI_COMMIT 复制回内容但不释放elems缓冲区
JNI_ABORT 释放缓冲区而不复制回可能的更改

在大多数情况下,程序员将"0"作为mode参数传递,以确保对固定和复制数组的行为一致。其他选项可以让程序员更加控制内存管理,但应极度小心使用。如果在elemsarray中元素的副本时,将JNI_COMMIT作为mode参数传递,则应该进行最终调用,调用Release<PrimitiveType>ArrayElements并传递一个"0"或JNI_ABORTmode参数,以释放elems缓冲区。

下表描述了组成原始数组释放器系列的具体例程。您应进行以下替换:

Release<PrimitiveType>ArrayElements 原始数组例程系列
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 原始数组例程系列
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:释放模式:0JNI_COMMITJNI_ABORT


Get<PrimitiveType>ArrayRegion 例程

void Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, NativeType *buf);

一组函数,将原始数组的区域复制到缓冲区中。

以下表描述了特定的原始数组元素访问器。您应进行以下替换:

Get<PrimitiveType>ArrayRegion 原始数组访问器例程系列
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 原始数组访问器例程系列
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 数组访问例程系列
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 数组访问例程系列
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可能会暂时禁用垃圾回收。

可以嵌套多对GetPrimtiveArrayCriticalReleasePrimitiveArrayCritical。例如:

  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:释放模式(参见原始数组释放模式):0JNI_COMMITJNI_ABORT。如果carray不是副本,则忽略。

自JDK/JRE 1.2起


注册本机方法


RegisterNatives

jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods);

使用clazz参数指定的类注册本机方法。 methods参数指定包含本机方法的名称、签名和函数指针的JNINativeMethod结构数组。 JNINativeMethod结构的namesignature字段是指向修改后的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不支持这种访问,则NewDirectByteBufferGetDirectBufferAddress函数必须始终返回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.Methodjava.lang.reflect.Constructor对象转换为方法ID。

链接:

在JNIEnv接口函数表中的索引为7。

参数:

env:JNI接口指针,不得为NULL

method:一个java.lang.reflect.Methodjava.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.Methodjava.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.Methodjava.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";失败返回负值。