JNI/NDK入门指南之jobject和jclass

      JNI/NDK入门指南之jobject和jclass

  在前面的章节JNI/NDK开发指南之JavaVM和JNIEnv中,我们详细介绍了一番JavaVM和JNIEnv,那么今天的篇章里面分别介绍一番jobject和jclass两个概念。



细说jobject和jclass

在JNI开发中JNI,实例引用(jobject)和类引用(jclass)让人觉得很困惑,至少我刚开始学习的时候是这么样的。jobject与jclass通常作为JNI函数的第二个参数,也许你在看Android源码或者其它人的相关代码时,你可能会留意到为啥JNI的第二个参数为啥通常是变化的呢,有时候是jobject有时候是jclass呢?这个要看该JNI函数所对应的函数在Java类中的申明,当所声明Native方法是静态方法时,对应参数jclass,因为静态方法不依赖对象实例,而依赖于类,所以参数中传递的是一个jclass类型。相反,如果声明的Native方法时非静态方法时,那么对应参数是jobject 。


1.jobject和jclass在jni.h中的定义

#ifdef __cplusplus
/*
 * Reference types, in C++
 */
class _jobject {};
class _jclass : public _jobject {};
typedef _jobject*       jobject;
typedef _jclass*        jclass;
...
#else /* not __cplusplus */
typedef void*           jobject;
typedef jobject         jclass;

...
#endif /* not __cplusplus */

定义比较简单就不一一细说了。


2.实例引用和类引用在JNI中函数体现

实例引用和java.lang.Object类或它的子类的实例对应。类引用与java.lang.Class实例对应,它代表着类的类型。一个操作如GetFieldID,需要参数jclass,是一个类操作,因为它从一个类中获得field的描述。与此相反,GetIntField需要参数jobject,这是一个实例操作,因为它从这个实例中获得这个field的值。在所有的JNI方法中jobject和实例操作的结合和jclass和类操作的结合保持一致。所以是很容易记住类操作与实例操作的不同的。上述所描述的可以在JNI中函数体现出下,如下:

	//下述函数都是类引用有关系,所以参数都是jclass
    jfieldID    (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);
    jobject     (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...);
    jobject     (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);

	//下述函数都是和实例引用有关系,所以参数都是jobject
	jobject     (*GetObjectField)(JNIEnv*, jobject, jfieldID);
	jobject     (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
	object     (*GetObjectField)(JNIEnv*, jobject, jfieldID);
	

3.简单介绍静态方法和实例方法的区别:

静态方法与静态变量一样,属于类本身,而不属于那个类的一个对象。调用一个被定义为static的方法,可以通过在它前面加上这个类的名称,也可以像调用非静态方法一样通过类对象调用。
实例方法必须通过类的实例来使用。实例方法可以使用类的非静态成员,也可以使用类的静态成员。
类的静态方法,静态变量是在类装载的时候装载的。但是要特别注意,类的静态变量是该类的对象所共有的,即是所有对象共享变量。所以建议尽量少用静态变量。尽量在静态方法中使用内部变量。

其中static关键字即表示静态的。声明静态方法的语法如下:
<访问修饰符>static返回类型 方法名(参数列表)
{//方法体}

静态方法与实例方法唯一不同的,就是静态方法在返回类型前加static关键字。静态方法的调用有两种途径:
(1) 通过类的实例对象去调用
调用格式为: 对象名.方法名
(2) 通过类名直接调用
调用格式为: 类名::方法名


4.实际案例分析

通过前面的章节,我想读者朋友们一定对jobject和jclass有了清晰的认识了,下面我们以实际code举例说明。
Java端代码:

public class Jobject_Jclass {
    public native static void fun();//类方法
    public native void fun1();//实例方法
}

JNI端代码:
通过javah命令生成头文件,生成的头文件如下,注意这里的第二个参数,你会发现原来真的如此,诚不欺我啊。

/*
 * Class:     com_xxx_api_binder_Jobject_Jclass
 * Method:    fun
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_xxx_api_binder_Jobject_1Jclass_fun
  (JNIEnv *, jclass);

/*
 * Class:     com_xxx_api_binder_Jobject_Jclass
 * Method:    fun1
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_xxx_api_binder_Jobject_1Jclass_fun1
  (JNIEnv *, jobject);


写在最后

好了,关于jobject和jclass到这里就要告一段落了。下面让我们再次总结一下关于jobject和jclass的区别:
当Java中定义的native方法为静态方法时,则第二个参数为jclass,jclass代表native方法所属类的class本身。
当Java中定义的native方法为非静态方法时,则第二个参数为jobject,jobject代表native方法所属类的实例对象。
最后留下一个问题,jclass和jobject可以相互转换吗,如果可以转换具体是通过什么方式呢?

你可能感兴趣的:(JNI/NDK入门指南)