Android JNI开发摘录(三)之JNI中的Java对象

      JNI中的Java对象

    Java本机接口提供了一个函数集来处理Java对象(使用方法/域)、句柄异常和用于线程的数据同步。这些函数在本机提供更好的访问Java对象的能力,允许用于更复杂的应用程序。这些函数的用法之一是被用来产生一个Java方法的回调,或者产生通信信息的回调。

     1.访问JNI中的域

     在Java类中有两种成员变量类型:静态域,它们属于类;非静态域,它们属于单个对象。为了可以访问一个域,必须向GetFieldID或GetStaticFieldID传递一个域描述符以及域的名称。域描述符是完整描述域类型的一个或多个字符。例如,域int的域描述符是I。用于数组的域描述符是以字符 [ 为前缀,用于数组的每一维。例如,int[]的域描述符是[I,int[][]的域描述符是[[I。对于引用类型,使用了类的完整限制符名称,但是点号被正斜杠替换,描述符将在开始被一个L,在结尾被一个分号所包围。例如,类型java.lang.Integer的域描述符是Ljava/lang/Integer。基本类型域描述符如下表:

基本类型

域描述符

boolean

Z

byte

B

char

C

short

S

int

I

long

J

float

F

double

D

       2.访问域的函数

       (1).下面的函数向指定域返回一个句柄,以便用于Get以及Set函数。GetObjectClass函数可以用来获取一个适合于该函数第一个参数的jclass。name是域的名称,sig是域描述符。如果函数失败,返回NULL:

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

     

      (2).下面的函数返回属于Java对象obj的,被fieldID指定的一个特定域:

[NativeType] Get[Type]Field(jobject obj, jfieldID fieldID);

     (3).SetField函数将属于Java对象obj的,被fieldID指定的一个特定域的值设置为val:

void Set[Type]Field(jobject obj,jfieldID fieldID, [NativeType] val);

    (4)GetStaticFieldID函数同GetFieldID函数功能相同,但它用于获取一个静态域的句柄:

jfieldID GetStaticFieldID(jclass clazz,const char *name, const char *sig);



    (5)GetStaticField函数返回属于clazz描述的类,fieldID指定的一个静态域的值:

[NativeType] GetStatic[Type]Field(jclass clazz,jfieldID fieldID);

    (6).SetStaticField函数设置属于clazz描述的类,fieldID指定一个静态域的值:

void SetStatic[Type]Field(jclass clazz, jfieldID fieldID, [NativeType] value);

    3.使用JNI调用Java方法

    使用JNI可以调用Java中的静态及非静态方法,这时需要使用方法的名称和方法描述符来获得特定Java方法的句柄,然后才能通过CallMethod函数调用该Java方法。

    方法描述符通过将所有方法的参数类型放置到一个单一圆括号集中,然后在圆括号之后指定返回类型而形成。用于参数的类型以及返回类型使用在前面描述过的域描述符。如果方法返回void,则描述符就是V。若方法没有任何参数,则圆括号中为空。用于熟悉的main方法的方法描述符是([Ljava/lang/String;)V。如果希望调用构造函数,使用方法名<init>,对于静态构造函数,则使用<clinit>。

    JNI调用Java方法的步骤:

     获取方法和变量描述符的编译命令:javap -s -classpath . [PacketName+"."+Library Name]  如:javap -s -classpath . com.example.MyProject.MyLibrary

    (1).获取要调用方法所在的类:

jclass GetObjectClass(jobject obj);

   (2).通过jclass获取要调用的方法的methodID,即方法句柄:

/**

*使用步骤(1)获取的jclass

*方法名称

*方法描述符

*/

jmethod GetMethodID(jclass clazz,const char *name,const char *sig);

jmethod GetStaticMethodID(jclass clazz,const char* name,const char *sig);

    (3).通过方法句柄调用方法,注意:如果希望调用一个构造函数或一个私有方法,方法ID将会基于实际对象的类获得,而不是基于对象的一个超类。

    

/**

*java环境传入的jobject

*方法句柄

*/参数:接受大量参数,并将这些参数直接传送到Java方法中

[NativeType] Call[Type]Method(jobject obj, jmethodID methodID,…);

/**

*该方法将参数列表作为一个va_list结构接受,该结构是随同参数列

*表预包装的。

*/

[NativeType] Call[Type]MethodV(jobject obj,jmethodID methodID,va_list args);

/**

*该方法将参数作为一个jvalue数组接受,它是可以使用任意本机数据*类型版本的Java数据类型形式的一个联合(union),包括jobject。

*/

[NativeType] Call[Type]MethodA(jobject obj, jmethodID methodID, const jvalue *args);



/**

*下面三个方法也调用对象方法的一个实例,但是调用的Java方法是

*基于jclass数的。这些函数可以在对象的层次结构中调用一个指定的方法,而不是仅仅基于对象的类调用一个方法。

*jclass应通过传入要调用的方法所在的类的实例来获得。

*/

[NativeType] CallNonvirtual[Type]Method(jobject obj, jclass clazz, jmethodID methodID, …);



[NativeType] CallNonvirtual[Type]MethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);



[NativeType] CallNonvirtual[Type]MethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue *args);





/**

*下面的函数调用属于传入的clazz类的一个静态方法。使用Get

*StaticMethodID来获得方法句柄。

*/

[NativeType] CallStatic[Type]Method(jclass clazz, jmethodID methodID, …);



[NativeType] CallStatic[Type]MethodV(jclass clazz, jmethodID methodID, va_list args);



[NativeType] CallStatic[Type]MethodA(jclass clazz, jmethodID methodID, const jvalue *args);
原文地址:https://www.cnblogs.com/oxgen/p/2381018.html