本系列文章如下:
Android JNI学习(一)——NDK与JNI基础
Android JNI学习(二)——实战JNI之“hello world”
Android JNI学习(三)——Java与Native相互调用
Android JNI学习(四)——JNI的常用方法的中文API
本文主要是结合 JNI的常用接口文档 进行的翻译主要是帮助我们更好的理解JNI中常用的API。具体如下:
每个函数都可以通过JNIEnv参数访问,JNIEnv类型是指向一个存放所有JNI接口指针的指针,其定义如下:
typedef const struct JNINativeInterface *JNIEnv;
虚拟机初始化函数表,如下面代码所示,前三个条目是为了将来和COM兼容而保留的。另外,我们在函数表的开头附近保留了一些额外的NULL条目,例如,可以在FindClass之后添加未来与类相关的JNI操作,而不是在表的末尾。请注意,函数表可以在所有JNI接口指针之间共享。
首先我们来看下JNINativeInterface:
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
};
下面我们就详细介绍下
在JNIEnv指针中,有个函数用于获取JNI的版本:
jint GetVersion(JNIEnv *env);
该方法主要返回本地JNI方法接口的版本信息。在不同的JDK环境下返回值是不同的,具体如下:
上面这些数字可不是我乱拍的,其实是早就被定义为一个宏了,如下:
#define JNI_VERSION_1_1 0x00010001
#define JNI_VERSION_1_2 0x00010002
/* Error codes */
#define JNI_EDETACHED (-2) /* thread detached from the VM */
#define JNI_EVERSION (-3) /* JNI version error
SINCE JDK/JRE 1.4:
#define JNI_VERSION_1_4 0x00010004
SINCE JDK/JRE 1.6:
#define JNI_VERSION_1_6 0x00010006
jclass DefineClass(JNIEnv *env,const char* name,jobject loader,const jbyte *buf, jsize bufLen)
这个函数,主要是从包含数据的buffer中加载类,该buffer包含类调用时未被虚拟机所引用的原始类数据。
入参解释:
返回:Java类对象,当错误出现时返回NULL
可能抛出的异常:
jclass FindClass(JNIEnv *env,const char *name);
这里面有两种情况一个是JDK release1.1,另外一种是JDK release 1.2。从JDK release 1.1,该函数加载一个本地定义类,它搜索CLASSPATH环境变量里的目录及zip文件查找特定名字的类。自从Java 2 release 1.2,Java安全模型允许非系统类加载跟调用本地方法。FindClass定义与当前本地方法关联的类加载,也就是声明本地方法的类的类加载类。如果本地方法属于系统类,则不会涉及类加载器;否则,将调用适当的类加载来加载和链接指定的类。从Java 2 SDK1.2版本开始,通过调用接口调用FindClass时,没有当前的本机方法或关联的的类加载器。在这种情况下,使用ClassLoader.getSystemClassLoader的结果。这是虚拟机为应用程序创建的类加载器,并且能够找到java.class.path属性列出的类。
入参解释:
返回:
可能抛出的异常:
jclass GetSuperclass(JNIEnv *env,jclass clazz);
如果clazz不是Object类,则此函数将返回表示该clazz的父类的Class对象,如果该类是Object,或者clazz代表接口,则此函数返回NULL。
入参解释:
返回:
jboolean IsAssignableFrom(JNIEnv *env,jclass clazz1,jclass clazz2);
判断clazz1的对象是否可以安全地转化为clazz2的对象
入参解释:
返回:
如果满足以下任一条件,则返回JNI_TRUE:
jint Throw(JNIEnv *env,jthrowable obj);
传入一个jthrowable对象,并且在JNI并将其抛起:
入参解释:
返回:
可能抛出的异常:
jint ThrowNew(JNIEnv *env,jclass clazz,const char* message);
传入一个message,并用其构造一个异常并且抛出。
入参解释:
返回:
可能抛出的异常:
jthrowable ExceptionOccurred(JNIEnv *env);
检测是否发生了异常,如果发生了,则返回该异常的引用(再调用ExceptionClear()函数前,或者Java处理异常前),如果没有发生异常,则返回NULL。
入参解释:
返回:
void ExceptionDescribe(JNIEnv *env)
打印这个异常的堆栈信息。
入参解释:
void ExceptionClear(JNIEnv *env);
清除正在抛出的异常,如果当前没有异常被抛出,这个函数不起作用。
入参解释:
void FatalError(JNIEnv *env,const char* msg);
致命异常,用于输出一个异常信息,并终止当前VM实例,即退出程序。
入参解释:
jboolean ExceptionCheck(JNIEnv *env);
检查是否已经发生了异常,如果已经发生了异常,则返回JNI_TRUE,否则返回JNI_FALSE。
入参解释:
返回:
jobject NewGlobalRef(JNIEnv *env,object obj);
给对象obj创建一个全局引用,obj可以是全局或局部引用。全局引用必须通过DeleteGlobalRef()显示处理。
参数解释:
返回:
void DeleteGlobalRef(JNIEnv *env,jobject globalRef);
删除全局引用。
参数解释:
局部引用只在本地接口调用时的生命周期内有效,当本地方法返回时,它们会被自动释放。每个局部引用都会消耗一定的虚拟机资源,虽然局部引用可以被自动销毁,但是程序员也需要注意不要在本地方法中过度分配局部引用,过度分配局部引用会导致虚拟机在执行本地方法时内存溢出。
void DeleteLocalRef(JNIEnv *env, jobject localRef);
通过localRef删除局部引用。
参数解释
JDK/JRE 1.1提供了上面的DeleteLocalRef函数,这样程序员就可以手动删除本地引用。
从JDK/JRE 1.2开始,提供可一组生命周期管理的函数,他们是下面四个函数。
jint EnsureLocalCapacity(JNIEnv *env,jint capacity);
在当前线程中,通过传入一个容量capacity,,限制局部引用创建的数量。成功则返回0,否则返回一个负数,并抛出一个OutOfMemoryError。VM会自动确保至少可以创建16个局部引用。
参数解释
返回:
为了向后兼容,如果虚拟机创建了超出容量的局部引用。VM调用FatalError,来保证不能创建更多的本地引用。(如果是debug模式,虚拟机会向用户发出warning,并提示创建了更多的局部引用,在JDK中,程序员可以提供-verbose:jni命令行选项来打开这个消息)
jint PushLocalFram(JNIEnv *env ,jint capacity);
在已经设置设置了局部变量容量的情况下, 重新创建一个局部变量容器。成功返回0,失败返回一个负数并抛出一个OutOfMemoryError异常。
注意:当前的局部帧中,前面的局部帧创建的局部引用仍然是有效的
参数解释
jobject PopLocalFrame(JNIEnv *env,jobject result)
弹出当前的局部引用帧,并且释放所有的局部引用。返回在之前局部引用帧与给定result对象对应的局部引用。如果不需要返回任何引用,则设置result为NULL。
参数解释
(七)、创建一个局部引用
jobject NewLocalRef(JNIEnv *env,jobject ref);
创建一个引用自ref的局部引用。ref可以是全局或者局部引用,如果ref为NULL,则返回NULL。
参数解释
弱全局引用是一种特殊的全局引用,不像一般的全局引用,一个弱全局引用允许底层Java对象能够被垃圾回收。弱全局引用能够应用在任何全局或局部引用被使用的地方。当垃圾回收器运行的时候,如果对象只被弱引用所引用时,它将释放底层变量。一个弱全局引用指向一个被释放的对象相当于等于NULL。编程人员可以通过使用isSampleObject对比弱引用和NULL来检测一个弱全局应用是否指向一个被释放的对象。弱全局引用在JNI中是Java弱引用的一个简化版本,在Java平台API中有有效。
当Native方法正在运行的时候,垃圾回收器可能正在工作,被弱引用所指向的对象可能在任何时候被释放。弱全局引用能够应用在任何全局引用所使用的地方,通常是不太适合那么做的,因为它们可能在不注意的时候变成NULL。
当IsSampleObject能够识别一个弱全局引用是不是指向一个被释放的对象,但是这不妨碍这个对象在被检测之后马上被释放。这就说明了,程序员不能依赖这个方法来识别一个弱全局引用是否能够在后续的JNI函数调用中被使用。
如果想解决上述的问题,建议使用JNI函数NewLocalRef或者NewGlobalRef来用标准的全局也引用或者局部引用来指向相同的对象。如果这个独享已经被释放了这些函数会返回NULL。否则会返回一个强引用(这样就可以保证这个对象不会被释放)。当不需要访问这个对象时,新的引用必须显式被删除。
jweak NewWeakGlobalRef(JNIEnv *env,jobject obj);
创建一个新的弱全局引用。如果obj指向NULL,则返回NULL。如果VM内存溢出,将会抛出异常OutOfMemoryError。
参数解释
返回:
void DeleteWeakGlobalRef(JNIEnv *env,jweak obj);
VM根据所给定的弱全局引用删除对应的资源。
参数解释
jobject AllocObject(JNIEnv *env,jclass clazz);
不借助任何构造函数的情况下分配一个新的Java对象,返回对象的一个引用。
参数解释:
返回:
异常:
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对象,methodID表明需要调用一个构造函数。这个ID必须通过调用GetMethodID()获得,GetMethodID()为函数名,void(V)为返回值。clazz参数不能指向一个数组类。
参数解释:
附加参数:
返回:
异常:
jclass GetObjectClass(JNIEnv *env,object obj);
返回obj对应的类。
参数解释
返回:
jobjectRefType GetObjectRefType(JNIEnv *env,jobject obj);
返回obj参数所指向对象的类型,参数obj可以是局部变量,全局变量或者若全局引用。
参数解释
返回:
无效的引用就是没有引用的引用。也就是说,obj的指针没有指向内存中创建函数时候的地址,或者已经从JNI函数中返回了。所以说NULL就是无效的引用。并且GetObjectRefType(env,NULL)将返回类型是JNIInvalidRefType。但是空引用返回的不是JNIInvalidRefType,而是它被创建时候的引用类型。
PS:不能在引用在删除的时候,调用该函数
jboolean IsInstanceOf(JNIEnv *env, jobject obj,jclass clazz);
测试obj是否是clazz的一个实例。
参数:
返回:
如果obj是clazz的实例,则返回JNI_TRUE;否则则返回JNI_FALSE;一个空对象可以是任何类的实例。
jboolean IsSampleObject(JNIEnv *env,jobject ref1,jobject ref2);
判断两个引用是否指向同一个对象。
参数解释:
返回:
jfieldID GetFieldID(JNIEnv *env,jclass clazz,const char *name,const char *sig);
获取某个类的非静态属性id。通过方法属性名以及属性的签名(也就是属性的类型),来确定对应的是哪个属性。通过检索这个属性ID,我们就可以调用Get
参数解释:
返回
异常:
PS:GetFieldID()可能会导致还未初始化的类开始初始化,同时在获取数组的长度不能使用GetFieldID(),而应该使用GetArrayLength()。
NativeType GetField(JNIEnv *env,jobject obj,jfieldID fielD);
返回某个类的非静态属性的值,这是一组函数的简称,具体如下:
jobject GetObjectField(JNIEnv *env,jobject obj,jfieldID fielD)
jboolean GetBooleanField(JNIEnv *env,jobject obj,jfieldID fielD)
jbyte GetByteField(JNIEnv *env,jobject obj,jfieldID fielD)
jchar GetCharField(JNIEnv *env,jobject obj,jfieldID fielD)
jshort GetShortField(JNIEnv *env,jobject obj,jfieldID fielD)
jint GetIntField(JNIEnv *env,jobject obj,jfieldID fielD)
jlong GetLongField(JNIEnv *env,jobject obj,jfieldID fielD)
jfloat GetFloatField(JNIEnv *env,jobject obj,jfieldID fielD)
jdouble GetDoubleField(JNIEnv *env,jobject obj,jfieldID fielD)
参数解释:
返回:
void SetField(JNIEnv *env,jobject obj,jfieldID fieldID,NativeType value)
设置某个类的的非静态属性的值。其中具体哪个属性通过GetFieldID()来确定哪个属性。这是一组函数的简称,具体如下:
void SetObjectField(jobject)
void SetBooleanField(jboolean)
void SetByteField(jbyte)
void SetCharField(jchar)
void SetShortField(jshort)
void SetIntField(jint)
void SetLongField(jlong)
void SetFloatField(jfloat)
void SetDoubleField(jdouble)
参数解释:
jmethodID GetMethodID(JNIEnv *env,jclass clazz,const char*name,const char* sig);
返回某个类或者接口的方法ID,该方法可以是被定义在clazz的父类中,然后被clazz继承。我们是根据方法的名字以及签名来确定一个方法的。
GetMethodID()会造成还未初始化的类,进行初始化。
如果想获取构造函数的ID,请提供init作为方法名称,并将void(V)作为返回类型。
参数解释:
返回:
异常:
NativeType CallMethod(JNIEnv *env,jobject obj,jmethodID methodID,...);
NativeType CallMethodA(JNIEnv *env,jobjct obj,jmethodID methodID ,const jvalue *args);
NativeType CallMethodV(JNEnv *env,jobject obj,jmethodID methodID,va_list args);
这一些列都是在native中调用Java对象的某个非静态方法,它们的不同点在于传参不同。是根据方法ID来指定对应的Java对象的某个方法。methodID参数需要调用GetMethodID()获取。
当需要调用某个"private"函数或者构造函数时,这个methodID必须是obj类的方法,不能是它的父类的方法。
下面我们来看下他们的不同点
CallMethod Routine Name Native Type
CallVoidMethod()
CallVoidMethodA() void
CallVoidMethodV()
CallObjectMethod()
CallObjectMethodA() jobject
CallObjectMethodV()
CallBooleanMethod()
CallBooleanMethodA() jboolean
CallBooleanMethodV()
CallByteMethod()
CallByteMethodA() jbyte
CallByteMethodV()
CallCharMethod()
CallCharMethodA() jchar
CallCharMethodV()
CallShortMethod()
CallShortMethodA() jshort
CallShortMethodV()
CallIntMethod()
CallIntMethodA() jint
CallIntMethodV()
CallLongMethod()
CallLongMethodA()
CallLongMethodV()
CallFloatMethod()
CallFloatMethodA() jlong
CallFloatMethodV()
CallDoubleMethod()
CallDoubleMethodA() jfloat
CallDoubleMethodV()
参数解释:
返回:
异常:
调用父类中的实例方法,如下系列:
CallNonvirtualMethod
CallNonvirtualMethodA
CallNonvirtualMethodV
具体如下:
NativeType CallNonvirtualMethod(JNIEnv *env,jobject obj,jclass clazz,jmethodID methodID,....);
NativeType CallNonvirtualMethodA(JNIEnv *env,jobject obj,jclass clazz,jmethodID methodID,const jvalue *args);
NativeType CallNonvirtualMethodV(JNIEnv *env, jobject obj,
jclass clazz, jmethodID methodID, va_list args);
这一系列操作就是根据特定的类,和其方法ID来调用Java对象的实例的非静态方法,methodID参数需要调用GetMethodID()获取。
CallNonvirtual
下面我们来看下他们的不同点
将上面这系列方法展开如下:
CallNonvirtualMethod Routine Name Native Type
CallNonvirtualVoidMethod()
CallNonvirtualVoidMethodA() void
CallNonvirtualVoidMethodV()
CallNonvirtualObjectMethod()
CallNonvirtualObjectMethodA() jobject
CallNonvirtualObjectMethodV()
CallNonvirtualBooleanMethod()
CallNonvirtualBooleanMethodA() jboolean
CallNonvirtualBooleanMethodV()
CallNonvirtualByteMethod()
CallNonvirtualByteMethodA() jbyte
CallNonvirtualByteMethodV()
CallNonvirtualCharMethod()
CallNonvirtualCharMethodA() jchar
CallNonvirtualCharMethodV()
CallNonvirtualShortMethod()
CallNonvirtualShortMethodA() jshort
CallNonvirtualShortMethodV()
CallNonvirtualIntMethod()
CallNonvirtualIntMethodA() jint
CallNonvirtualIntMethodV()
CallNonvirtualLongMethod()
CallNonvirtualLongMethodA() jlong
CallNonvirtualLongMethodV()
CallNonvirtualFloatMethod()
CallNonvirtualFloatMethodA() jfloat
CallNonvirtualFloatMethodV()
CallNonvirtualDoubleMethod()
CallNonvirtualDoubleMethodA() jdouble
CallNonvirtualDoubleMethodV()
参数解释:
返回:
抛出异常:
jfieldID GetStaticFieldID(JNIEnv *env,jclass clazz,const char* name,const char *sig);
获取某个类的某个静态属性ID,根据属性名以及标签来确定是哪个属性。GetStaticField()和SetStaticField()通过使用属性ID来对属性进行操作的。如果这个类还没有初始化,直接调用GetStaticFieldID()会引起这个类进行初始化。
参数解释:
返回:
异常:
NativeType GetStaticField(JNIEnv *env,jclass clazz,jfieldID fieldID);
这个系列返回一个对象的静态属性的值。可以通过GetStaticFieldID()来获取静态属性的的ID,有了这个ID,我们就可以获取这个对其进行操作了。
下面表明了函数名和函数的返回值,所以只需要替换GetStatic
GetStaticField Routine Name Native Type
GetStaticObjectField() jobject
GetStaticBooleanField() jboolean
GetStaticByteField() jbyte
GetStaticCharField() jchar
GetStaticShortField() jshort
GetStaticIntField() jint
GetStaticLongField() jlong
GetStaticFloatField() jfloat
GetStaticDoubleField() jdouble
参数解释:
返回:
void SetStaticField(JNIEnv *env,jclass clazz,jfieldID fieldID,NativeType value);
这个系列是设置类的静态属性的值。可以通过GetStaticFieldID()来获取静态属性的ID。
下面详细介绍了函数名和其值,你可以通过SetStatic
SetStaticField Routine Name NativeType
SetStaticObjectField() jobject
SetStaticBooleanField() jboolean
SetStaticByteField() jbyte
SetStaticCharField() jchar
SetStaticShortField() jshort
SetStaticIntField() jint
SetStaticLongField() jlong
SetStaticFloatField() jfloat
SetStaticDoubleField() jdouble
参数解释:
jmethodID GetStaticMethodID(JNIEnv *env,jclass clazz,const char *name,const char sig);
返回类的静态方法ID,通过它的方法名以及签名来确定哪个方法。如果这个类还没被初始化,调用GetStaticMethodID()将会导致这个类初始化。
参数解释:
返回:
异常:
NativeType CallStaticMethod(JNIEnv *env,jclass clazz,jmethodID methodID,...);
NativeType CallStaticMethodA(JNIEnv *env,jclass clazz,jmethodID methodID,... jvalue *args);
NativeType CallStaticMethodV(JNIEnv *env,jclass,jmethodID methodid, va_list args)
根据指定的方法ID,就可以操作Java对象的静态方法了。可以通过GetStaticMethodID()来获得methodID。方法的ID必须是clazz的,而不是其父类的方法ID。
下面就是详细的方法了:
CallStaticMethod Routine Name Native Type
CallStaticVoidMethod()
CallStaticVoidMethodA() void
CallStaticVoidMethodV()
CallStaticObjectMethod()
CallStaticObjectMethodA() jobject
CallStaticObjectMethodV()
CallStaticBooleanMethod()
CallStaticBooleanMethodA() jboolean
CallStaticBooleanMethodV()
CallStaticByteMethod()
CallStaticByteMethodA() jbyte
CallStaticByteMethodV()
CallStaticCharMethod()
CallStaticCharMethodA() jchar
CallStaticCharMethodV()
CallStaticShortMethod()
CallStaticShortMethodA() jshort
CallStaticShortMethodV()
CallStaticIntMethod()
CallStaticIntMethodA() jint
CallStaticIntMethodV()
CallStaticLongMethod()
CallStaticLongMethodA() jlong
CallStaticLongMethodV()
CallStaticFloatMethod()
CallStaticFloatMethodA() jfloat
CallStaticFloatMethodV()
CallStaticDoubleMethod()
CallStaticDoubleMethodA() jdouble
CallStaticDoubleMethodV()
参数解释:
返回:
异常:
jstring NewString(JNIEnv *env,const jchar *unicodeChars,jszie len);
参数解释:
返回:
异常:
jsize GetStringLength(JNIEnv *env,jstring string);
返回Java字符串的长度(unicode字符的个数)
参数解释:
返回:
const jchar* GetStringChar(JNIEnv *env,jstring string , jboolean *isCopy);
返回指向字符串的UNICODE字符数组的指针,该指针一直有效直到被ReleaseStringchars()函数调用。
如果isCopy为非空,则在复制完成后将isCopy设为JNI_TRUE。如果没有复制,则设为JNI_FALSE。
参数解释:
返回:
void ReleaseStringChars(JNIEnv *env,jstring string,const jchar *chars);
通过VM,native代码不会再访问chars了。参数chars是一个指针。可以通过GetStringChars()函数获得。
参数解释:
jstring NewStringUTF(JNIEnv *env,const char *bytes);
创建一个UTF-8的字符串。
参数解释:
返回:
异常:
jsize GetStringUTFLength(JNIEnv *env,jstring string);
以字节为单位,返回字符串UTF-8的长度。
参数解释:
返回:
const char *GetStringUFTChars(JNIEnv *env, jString string, jboolean *isCopy);
返回指向UTF-8字符数组的指针,除非该数组被ReleaseStringUTFChars()函数调用释放,否则一直有效。
如果isCopy不是NULL,*isCopy在赋值完成后即被设置为JNI_TRUE。如果未复制,则设置为JNI_FALSE。
参数解释:
返回:
void ReleaseStringUTFChars(JNIEnv *env,jstring string,const char *urf)
通过虚拟机,native代码不再访问了utf了。utf是一个指针,可以调用GetStringUTFChars()获取。
参数解释:
注意:在JDK/JRE 1.1,程序员可以在用户提供的缓冲区获取基本类型数组元素,从JDK/JRE1.2开始,提供了额外方法,这些方法允许在用户提供的缓冲区获取Unicode字符(UTF-16编码)或者是UTF-8的字符。这些方法如下:
void GetStringRegion(JNIEnv *env,jstring str,jsize start,jsize len,jchar *buf)
在str(Unicode字符)从start位置开始截取len长度放置在buf中。如果越界,则抛出StringIndexOutOfBoundsException。
void GetStringUTFRegion(JNIEnv *env,jstring str,jsize start ,jsize len,char *buf);
将str(Unicode字符串)从start位置开始截取len长度并且将其转换为UTF-8编码,然后将结果防止在buf中。
const jchar * GetStringCritical(JNIEnv *env,jstring string,jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env,jstring string,cost jchar * carray);
上面这两个函数有点类似于GetStringChars()和ReleaseStringChars()功能。如果可能的话虚拟机会返回一个指向字符串元素的指针;否则,则返回一个复制的副本。
GetStringChars()和ReleaseStringChars()这里两个函数有很大的限制。在使用这两个函数时,这两个函数中间的代码不能调用任何让线程阻塞或者等待JVM的其他线程的本地函数或者JNI函数。有了这些限制,JVM就可以在本地方法持有一个从GetStringCritical得到的字符串的指指针时,禁止GC。当GC被禁止时,任何线程如果出发GC的话,都会被阻塞。而GetStringChars()和ReleaseStringChars()这两个函数中间的任何本地代码都不可以执行会导致阻塞的调用或者为新对象在JVM中分配内存。否则,JVM有可能死锁,想象一下这样的场景:
GetStringChars()和ReleaseStringChars()的交替迭代调用是安全的,这种情况下,它们的使用必须有严格的顺序限制。而且,我们一定要记住检查是否因为内存溢出而导致它的返回值是NULL。因为JVM在执行GetStringChars()这个函数时,仍有发生数据复制的可能性,尤其是当JVM在内存存储的数组不连续时,为了返回一个指向连续内存空间的指针,JVM必须复制所有数据。
总之,为了避免死锁,在GetStringChars()和ReleaseStringChars()之间不要调用任何JNI函数。
jsize GetArrayLength(JNIEnv *env,jarray array)
返回数组的长度。
参数解释:
返回:
jobjectArray NewObjectArray(JNIEnv *env,jsize length,jclass elementClass, jobject initialElement);
创建一个新的对象数组,它的元素的类型是elementClass,并且所有元素的默认值是initialElement。
参数解释:
返回:
异常:
jobject GetObjectArrayElement(JNIEnv *env,jobjectArray array,jsize index);
返回元素中某个位置的元素。
参数解释:
返回:
异常:
void SetObjectArrayElement(JNIEnv *env,jobjectArray array,jsize index,jobject value);
设置下标为index元素的值。
参数解释:
异常:
ArrayType NewArray(JNIEnv *env,jsize length);
用于构造基本类型数组对象的一系列操作。下面说明了特定基本类型数组的创建函数。可以把New
NewArray Routines Array Type
NewBooleanArray() jbooleanArray
NewByteArray() jbyteArray
NewCharArray() jcharArray
NewShortArray() jshortArray
NewIntArray() jintArray
NewLongArray() jlongArray
NewFloatArray() jfloatArray
NewDoubleArray() jdoubleArray
参数解释:
返回:
NativeType * GetArrayElements(JNIEnv *env,ArrayType array,jboolean * isCopy);
一组返回基本类型数组体的函数。结果在调用相应的 Release
如果isCopy不是NULL,*isCopy在复制完成后即被设为JNI_TRUE。如果未复制,则设为JNI_FALSE。
下面说明了特定的基本类型数组元素的具体函数:
不管布尔数组在Java虚拟机总如何表示,GetBooleanArrayElements()将始终返回一个jboolean类型的指针,其中每一个字节代表一个元素(开包表示)。内存中将确保所有其他类型的数组为连续的。
GetArrayElements Routines Array Type Native Type
GetBooleanArrayElements() jbooleanArray jboolean
GetByteArrayElements() jbyteArray jbyte
GetCharArrayElements() jcharArray jchar
GetShortArrayElements() jshortArray jshort
GetIntArrayElements() jintArray jint
GetLongArrayElements() jlongArray jlong
GetFloatArrayElements() jfloatArray jfloat
GetDoubleArrayElements() jdoubleArray jdouble
参数解释:
返回:
void ReleaseArrayElements(JNIEnv *env,ArrayType array,NativeType *elems,jint mode);
通知虚拟机Native不再访问数组的元素了。elems参数是使用相应的Get
mode的取值 有如下3种情况:
大多数情况下,程序员将“0”作为参数传递,因为这样可以确保固定和复制数组的一致行为。其他选项可以让程序员更好的控制内存。
下面说明了特定的基本类型数组元素的具体函数:
下面描述了基本类型数组释放的详情。 您应该进行以下替换:
ReleaseArrayElements Routines Array Type Native Type
ReleaseBooleanArrayElements() jbooleanArray jboolean
ReleaseByteArrayElements() jbyteArray jbyte
ReleaseCharArrayElements() jcharArray jchar
ReleaseShortArrayElements() jshortArray jshort
ReleaseIntArrayElements() jintArray jint
ReleaseLongArrayElements() jlongArray jlong
ReleaseFloatArrayElements() jfloatArray jfloat
ReleaseDoubleArrayElements() jdoubleArray jdouble
参数解释:
void Get ArrayRegion(JNIEnv *env,ArrayType array,jsize start,jsize len,NativeType *buf);
复制基本类型的数组给buff
下面说明了特定的基本类型数组元素的具体函数:
GetArrayRegion Routine Array Type Native Type
GetBooleanArrayRegion() jbooleanArray jboolean
GetByteArrayRegion() jbyteArray jbyte
GetCharArrayRegion() jcharArray jchar
GetShortArrayRegion() jshortArray jhort
GetIntArrayRegion() jintArray jint
GetLongArrayRegion() jlongArray jlong
GetFloatArrayRegion() jfloatArray jloat
GetDoubleArrayRegion() jdoubleArray jdouble
参数解释:
异常:
void Set ArrayRegion(JNIEnv *env,ArrayType array,jsize start,jsize len,const NativeType *buf);
主要是冲缓冲区复制基本类型的数组的函数。
下面说明了特定的基本类型数组元素的具体函数:
SetArrayRegion Routine Array Type Native Type
SetBooleanArrayRegion() jbooleanArray jboolean
SetByteArrayRegion() jbyteArray jbyte
SetCharArrayRegion() jcharArray jchar
SetShortArrayRegion() jshortArray jshort
SetIntArrayRegion() jintArray jint
SetLongArrayRegion() jlongArray jlong
SetFloatArrayRegion() jfloatArray jfloat
SetDoubleArrayRegion() jdoubleArray jdouble
参数解释:
异常:
从JDK/JER 1.1开始提供Get/Release
从JDK/JRE 1.3 开始引入新的功能即便VM不支持锁定,本地代码也可以获取数组元素的直接指针。
void *GetPrimitiveArrayCritical(JNIEnv *env,jarray array,jboolean *isCopy);
void ReleasePrimitiveArrayCritical(JNIEnv *env,jarray array,void *carray,jint mode);
虽然这两个函数与上面的Get/Release
在调用GetPrimitiveArrayCritical之后,调用ReleasePrimitiveArrayCritical之前,这个区域是不能调用其他JNI函数,而且也不能调用任何可能导致线程阻塞病等待另一个Java线程的系统调用。
比如,当前线程不能调用read函数来读取,正在被其他所写入的stream。
jint RegisterNatives(JNIEnv *env,jclass clazz,const JNINativeMethod *methods,jint nMethod);
根据clazz参数注册本地方法,methods参数制定JNINativeMethod结构数组,该数组包含本地方法的名字、签名及函数指针。其中名字及签名是指向编码为“UTF-8”的指针;nMethod参数表明数组中本地方法的个数。
这里说下JNINativeMethod这个结构体:
typedef struct {
char *name;
char *signature;
void *fnPtr;
} JNINativeMethod;
参数解释:
返回;
异常:
jint UnregisterNatives(JNIEnv *env,jclass clazz);
注销本地方法。类回收之前还没有被函数注册的状态。该函数一般不能再Native代码中被调用,它为特定的程序提供了一种重加载重链接本地库的方法。
参数解释:
返回:
jint MonitorEnter(JNIEnv *env,jobject obj);
obj引用的底层Java对象关联的监视器。obj引用不能为空。每个Java对象都有一个相关的监视器。如果当前线程已经有关联到obj的监视器,它将添加监视器的计数器来表示这个线程进入监视器的次数。如果关联至obj的监视器不属于任何线程,那当前线程将变成该监视器的拥有者,并设置计数器为1,如果其他计数器已经拥有了这个监视器,当前线程将进行等待直到监视器被释放,然后再获得监视器的拥有权。
通过MonitorEnter JNI函数调用的监视器不能用monitorexitJava虚拟机指令或者同步方法退出。MonitorEnterJNI函数调用和monitorenter Java虚拟机指令可能用同样的对象竞争地进入监视器。
为了避免死锁,通过MoniterEnterJNI函数调用进入的监视器必须用MonitorExitJNI调用退出,除非DetachCurrentThread接口被隐式的调用来释放JNI监视器
参数解释:
返回:
jint MonitorExit(JNIEnv *env,jobject obj);
当前线程拥有与该obj关联的监视器,线程减少计数器的值来指示线程进入监视器的次数。如果计数器的值变为0,则线程释放该监视器。Native代码不能直接调用MonitorExit来释放监视器。而是应该通过同步方法来使用Java虚拟机指令来释放监视器
参数解释:
返回:
异常:
NIO相关操作允许Native代码直接访问java.nio的直接缓冲区。直接缓冲区的内容可能存在于普通的垃圾回收器以外的本地内存。有关直接缓冲区的信息,可以参考 NIO和java.nio.ByteBuffer类的规范。
在JDK/JRE 1.4中引入了新的JNI函数,允许检查和操作做直接缓冲区
每个Java虚拟机的实现都必须支持这些功能,但并不是每个实现都需要支持对直接缓冲区的JNI访问。如果JVM不支持这种访问,那么NewDirectByteBuffer和GetDirectBufferAddress函数必须始终返回NULL,并且GetDirectBufferCapacity函数必须始终返回-1。如果JVM确实支持这种访问,那么必须实现这三个函数才能返回合适的值。
jobject NewDirectByteBuffer(JNIEnv *env,void *address,jlong capacity);
分配并返回一个直接的java.nio.ByteBuffer内存块从内存地址address开始的capacity个字节.
调用这个函数并返回字节缓冲区的对象的Native代码必须保证缓冲区指向一个可靠的可被读写的内存区域。进入非法的内存位置有可能会返回任意数值,DNA不会有明显的印象,也有可能抛出异常。
参数解释:
返回:
返回一个新开辟的java.nio.ByteBuffer对象的本地引用。如果产生异常,则返回NULL。如果JVM不支持JNI访问直接缓冲区,也会返回NULL
异常:
如果缓冲区分配失败,则返回OutOfMemoryError
void* GetDirectBufferAddress(JNIEnv *env,jobject buf);
获取并返回java.nio.Buffer的内存初始地址。
该函数允许Native代码通过直接缓冲区对象访问Java代码的同一内存区域。
参数解释:
返回:
返回内存区域的初始地址。如果内存区域未定义,返回NULL,如果给定的对象不是java.nio.buffer,则返回NULL,如果虚拟机不支持JNI访问,则返回NULL。
jlong GetDirectBufferCapacity(JNIEnv *env,jobject buf);
获取并返回java.nio.Buffer的内存容量。该容量是内存区域可容纳的元素的个数
参数:
返回:
返回内存区域的容量。如果指定的对象不是java.nio.buffer,则返回-1,或者如果对象是未对齐的view buffer且处理器架构不支持对齐访问。如果虚拟机不支持JNI访问则返回-1。
如果程序员知道方法和属性的名称和类型,则直接使用JNI调用Java方法或者访问Java字段。Java核心反射API允许在运行时反射Java类。JNI提供了JNI中使用的字段和方法ID与Java Core Reflection API中使用的字段和方法对象之间的一组转换函数。
jmethodID FromReflectedMethod(JNIEnv *env,jobject method);
将java.lang.reflect.Method或者java.lang.reflect.Constructor对象转换为方法ID。
参数解释:
返回:
jfield FromReflectedField(JNIEnv *env,jobject field);
将java.lang.reflect.Field转化为ID。
参数解释:
返回:
jobject ToReflectedMethod(JNIEnv *env,jclass clazz,jmethodID methodID, jboolean isStatic);
将源自cls的方法ID转化为java.lang.reflect.Method或者java.lang.reflect.Constructor对象。如果方法ID指向一个静态属性,isStatic必须设置为JNI_TRUE,否则为JNI_FALSE。
参数解释:
返回
对应Java层 java.lang.reflect.Method或者java.lang.reflect.Constructor对象。如果失败,则返回0
异常:
如果内存不足,则抛出OutOfMemoryError。
jobject ToReflectedField(JNIEnv *env,jclass cls,jfieldID field,jboolean isStatic)
将来源于cls的属性ID转化为java.lang.reflect.Field对象。如果属性ID指向一个静态属性,isStatic必须设置为JNI_TRUE,否则为JNI_FALSE。
参数解释:
返回:
成功返回java.lang.reflect.Field对象,失败返回0
异常:
如果内存不足,则抛出OutOfMemoryError
jint GetJavaVM(JNIEnv *env,JavaVM **vm);
返回当前线程对应的java虚拟机接口。返回的结果保存在vm。
参数解释:
返回:
成功返回0,失败返回负数。