Android JNI开发摘录(六)之JNI线程、NIO、反射处理

    七.使用JNI进行高级编程

    JNI向本机例程程序员提供了其他几种能力。由于Java是一个多线程环境,与线程相关的例程在本机端是可用的。JNI也支持将本机例程单独公开给Java代码,而不是通过对System.load或者System.loadLibrary的调用使所有本机函数对于Java代码都立即可用。除了这些特性意外,Java还在本机公开反射库。

    1.Java线程

    由于Java是一个多线程环境,那么在一个系统中就会有一个或多个线程来调用本机方法。这就使得了解本机方法以及在一个本机库中类似于全局引用之类的内容是如何同Java中的线程相关联显得非常重要。指向Java环境的指针是特定于线程的,因此不要在一个线程中使用另一个线程的环境指针。如果打算从一个线程中传递一个本地引用到另一个线程,需要先将其转换到一个全局引用,因为本地引用也是特定于线程的。

    1)线程同步

     JNI提供两个函数来同步对象。MonitorEnter以及MonitorExit。这两个函数是只用于线程的函数,由于它们是时间关键的函数,因此它们在本机层次直接被公开。其他诸如等待以及通告等函数可以通过调用Java方法来实现。

  

 /*调用MonitorEnter函数等于在Java中使用synchronized(obj)。当前线程输入被指定对象的监控程序,除非另一个线程已经锁住该对象,此时当前线程将暂停直至另一个线程释放对象的监控程序。如果当前线程已经锁住对象的监控程序,则对于该函数对该对象的每一次调用计数器都将增1。函数成功则返回0,失败则返回一个负值。*/

jint MonitorEnter(jobject obj);

/*MonitorExit函数将对象的监控程序计数器减1。如果计数器值为0则释放当前线程在该对象上的锁。函数执行成功则返回0,失败返回一个负值。*/

jint MonitorExit(jobject obj);

 

     2.本机NIO的支持

     在Java1.4版本中引入的JNI有三个函数可以用于NIO的直接缓冲器。一个直接字节缓冲器是一个用于字节数据的容器。Java将尽力在它上面执行本机I/O操作。JNI定义了三个用于NIO操作的函数。

/*     基于到存储器地址的指针以及存储器长度(容量),函数分配并且返回一个新的Java.nio.ByteBuffer。如果函数没有针对当前Java虚拟机实现,则返回NULL,或者抛出一个异常。如果没有存储器可用,则将会抛出一个OutOfMemoryException。*/

jobject NewDirectByteBuffer(void* address, jlong capacity);

/* GetDirectBufferAddress函数返回一个指向被传入的java.nio.ByteBuffer对象的地址指针。如果函数尚未针对当前虚拟机实现,或者如果buf不是java.nio.ByteBuffer的一个对象,又或者存储器区尚未定义,则都将返回NULL。*/

void* GetDirectBufferAddress(jobject buf);

/*GetDirectBufferCapacity函数返回被传入的java.nio.ByteBuffer对象的容量(以字节计数)。如果函数没有针对当前环境实现,或者如果buf不是java.nio.ByteBuffer类型的对象返回-1。*/

jlong GetDirectBufferCapacity(jobject buf);

 

      3.手动注册本机方法

      JNI提供在运行时注册本机方法的一种方式。当一个本机应用在运行时初始化一个虚拟机实例时,这种动态注册特别有用。该应用程序中的本机方法无法被VM载入(因为它们不在本机库中),但是这些方法在手动注册之后就可以通过Java代码调用。可以多次注册一个本机方法,在运行时来修改它的实现。对于这些本机函数的唯一要求是它们都必须遵从JNICALL调用约定。

/*RegisterNatives被用来注册一个或多个本机方法。注册成功则返回0,否则返回一个负值。参数clazz是Java类的一个句柄,该类包含了需要被注册的本机方法。nMethod参数指定了在注册列表中本机方法的数量。methods参数是一个到本机方法(可以是一个或多个方法)列表的指针。该方法数组的每一个元素都是JNINativeMethod结构的一个实例。JNINativeMethod结构如下:*/

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

typedef struct

{

char* name;

char* signature;

void* fnPtr;

}JNINativeMethod;

/*串是UTF-8编码串。name成员包含到注册程序的本机方法名称(来自Java类),signature则是完整描述方法类型的方法描述符。fnPtr成员是一个指向C函数到注册程序的函数指针。隐藏在函数之后的这个指针必须遵循如下原形:*/

[ReturnType] (*fnPtr)(JNIEnv *env, jobject ObjectOrClass, …);

/*[ReturnType]必须是Java数据类型的本机对等类型之一。实现的所有本机方法的前两个参数分别是到Java环境的指针和调用该本机方法的类/对象的引用。用于常规参数的变量参数列表被传到方法中。*/

jint UnregisterNatives(jclass clazz);

/*除了在非常特殊的情况下,其他时候都不应该调用UnregisterNatives函数。该函数注销所有注册到被传入类的本机方法。如果成功则返回0,否则返回一个负值。*/



      4.反射

      JNI提供一个反射集函数来镜像Java API中的那些函数。使用这些函数可以发现有关类的一些信息,例如类的超类或者一个类型是否可以转换为其他类型等。这些函数同时也提供了将jmethodID以及jfieldID类型转换为他们对应的方法或者域,或者从这些方法或者域中转换回jmethodID以及jfieldID类型的功能。

/*

FindClass 函数针对传入的类名称搜索在CLASSPATH中找到的所有类/jar文件。如果类被找到,将会返回到该类的一个句柄。名称是一个UTF-8串,它包括了完整包名称以及类名称,但是点号将会被正斜杠所代替。如果没有发现类,将返回NULL,并且将会抛出如下异常之一:

ClassFormatError:请求的类不是一个有效类。

ClassCircularityError:类/接口是它自己的超类/超接口。

OutOfMemoryError:没有到该类的句柄存储器空间。

*/

jclass FindClass(const char* name);



/*GetObjectClass函数返回被传入对象类的一个句柄。*/

jclass GetObjectClass(jobject obj);



/*GetSuperclass函数返回被传入的类的超类的一个句柄。如果java.lang.Object被传入,或者一个接口被传入,将返回NULL。*/

jcalss GetSuperclass(jclass sub);



/*IsAssignableFrom函数用来判断由sub描述的一个类对象是否可以被成功转型为由sup描述的类。如果sub和sup是相同的类,或者sub是sup的一个子类,或者sub实现sup接口,则返回JNI_TRUE,否则返回JNI_FALSE。*/

jboolean IsAssignableFrom(jclass sub, jclass sup);



/*IsInstanceOf函数则在obj是clazz的一个实例时返回JNI_TURE,否则返回JNI_FALSE。向obj传入NULL总会使函数返回JNI_TRUE,因为空对象可以被转型为任意类。*/

jboolean IsInstanceOf(jobject obj, jclass clazz);



/*FromReflectedMethod函数接收一个到java.lang.reflect.Method的对象的句柄,并且返回一个jmethodID,它适合于在需要jmethodID的函数中调用。*/

jmethodID FromReflectedMethod(jobject method);



/*ToReflectedMethod函数接收一个到Java类的句柄和一个到特定方法(它可能是一个构造函数)的句柄,并且返回与该方法对应的java.lang.reflect.Method对象。如果方法是一个静态方法,则将isStatic设置为JNI_TRUE,否则设置为JNI_FALSE(或0)。如果函数失败,将返回NULL并且抛出OutOfMemoryException。*/

jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic);



/*FromReflectedField函数接收一个到java.lang.reflect.Field的对象的句柄,并且返回一个jfieldID,它适合于在一个需要jfieldID的函数中使用*/

jfieldID FromReflectedField(jobject field);



/*ToReflectedField函数接收一个到Java类的句柄和一个到特定域的句柄,并且返回对应于该域的java.lang.reflect.Field对象。如果域是静态域,则将isStatic设置为JNI_TRUE,否则设置为JNI_FALSE(或0)。如果函数失败,它将返回NULL并且抛出一个OutOfMemoryException。*/

jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic);



posted @ 2012-03-05 22:47  Oxgen  Views(3271)  Comments(0Edit  收藏  举报