Android JNI开发详解(6)-对象操作

原文出处:http://www.ccbu.cc/index.php/android/android-jni-object-operate.html

1. 对象操作基本步骤

Jni是沟通Java世界和Native世界的纽带,Java层调用本地方法只用调用Java中定义的本地(native)方法就可用了,那么,本地的C/C++代码如何调用Java层的代码呢?这就是本章节对象操作要解决阐述的内容。

一般的,C/C++层要调用Java层代码,需要进行以下步骤。

  1. 获取Java层对应的jclass,通过jclass来获取Java类的方法,属性。
  2. 获取Java层对象引用,如果Java层有传引用下来,则可用直接使用,否则就需要在C/C++层调用创建对象的接口来创建Java层对应类的对象。调用Java静态函数不需要对象引用。
  3. 调用Java层类的静态方法,或者Java层对象的方法。
  4. 处理返回值。

2. 类操作

2.1 函数列表

Jni中类操作相关的函数包括以下函数:

函数 说明
DefineClass 从原始类数据的缓冲区中加载类
FindClass 查找类
GetSuperclass 查找父类
IsAssignableFrom 类型判断

2.2 关于类名

Jni在加载或查找Java层类时,需要通过类的全名来进行加载,该类的全名为类包含包名的全路径,比如 java.lang.String类,那么类的全名则为java/lang/String

2.3 对应的C++函数定义如下:

/**
 * 从原始类数据的缓冲区中加载类
 * @param name 类的全名,必须是被UTF-8编码过的字符串。
 * @param loader 类加载器
 * @param buf 包含 .class 文件数据的缓冲区
 * @return java类对象。发生错误时返回NULL
 */
jclass DefineClass(const char *name, jobject loader, const jbyte* buf,
        jsize bufLen)

/**
 *  查找类
 * @param name 类的全名,必须是被UTF-8编码过的字符串。
 * @return 
 */
jclass FindClass(const char* name)

/**
 * 获取父类
 * @param clazz Java类对象
 * @return java类对象。clazz的父类或NULL
 */
jclass GetSuperclass(jclass clazz)

/**
 * 确定clazz1的对象是否可安全地强制转换为clazz2
 * @param clazz1 类的对象
 * @param clazz2 类的对象
 * @return 如果满足以下任一条件,则返回JNI_TRUE:
 *         1. 如果clazz1和clazz2是同一个Java类。 
 *         2. 如果clazz1是clazz2的子类
 *         3. 如果clazz1是clazz2接口的实现类
 */
jboolean IsAssignableFrom(jclass clazz1, jclass clazz2)

2.4 对应的C函数定义为:

jclass      (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*, jsize);
jclass      (*FindClass)(JNIEnv*, const char*);
jclass      (*GetSuperclass)(JNIEnv*, jclass);
jboolean    (*IsAssignableFrom)(JNIEnv*, jclass, jclass);
jclass      (*GetObjectClass)(JNIEnv*, jobject);

3. 对象操作

Jni中对象操作相关的函数主要包括:

函数 说明
AllocObject 直接创建Java对象
NewObject 根据某个构造函数来创建Java对象
NewObjectV 根据某个构造函数来创建Java对象
NewObjectA 根据某个构造函数来创建Java对象
GetObjectClass 获取指定类对象的类
IsInstanceOf 判断某个对象是否是某个“类”的子类

对应的C++函数定义如下:

/**
 * 不借助任何构造函数的情况下分配一个新的Java对象
 * @param clazz Java类对象
 * @return 返回一个Java对象实例,如果该对象无法被创建,则返回NULL
 */
jobject AllocObject(jclass clazz)

/**
 * 根据构造函数来创建Java对象
 * @param clazz Java类对象
 * @param methodID 构造函数的方法ID
 * @param ... 构造函数的输入参数(可变参数)
 * @return 返回一个Java对象实例,如果无法创建该对象,则返回NULL
 */
jobject NewObject(jclass clazz, jmethodID methodID, ...)

/**
 * 根据构造函数来创建Java对象
 * @param clazz Java类对象
 * @param methodID 构造函数的方法ID
 * @param args 构造函数的输入参数(va_list)
 * @return 返回一个Java对象实例,如果无法创建该对象,则返回NULL
 */
jobject NewObjectV(jclass clazz, jmethodID methodID, va_list args)

/**
 * 根据构造函数来创建Java对象
 * @param clazz Java类对象
 * @param methodID 构造函数的方法ID
 * @param args 构造函数的输入参数(参数数组)
 * @return 返回一个Java对象实例,如果无法创建该对象,则返回NULL
 */
jobject NewObjectA(jclass clazz, jmethodID methodID, const jvalue* args)

/**
 * 通过对象获取类
 * @param obj 类的对象
 * @return Java 类对象。
 */
jclass GetObjectClass(jobject obj)

/**
 * 判断某个对象是否是某个“类”的子类
 * @param obj Java对象实例
 * @param clazz Java类对象
 * @return 
 */
jboolean IsInstanceOf(jobject obj, jclass clazz)

对应的C函数定义为:

jobject     (*AllocObject)(JNIEnv*, jclass);
jobject     (*NewObject)(JNIEnv*, jclass, jmethodID, ...);
jobject     (*NewObjectV)(JNIEnv*, jclass, jmethodID, va_list);
jobject     (*NewObjectA)(JNIEnv*, jclass, jmethodID, const jvalue*);
jclass      (*GetObjectClass)(JNIEnv*, jobject);
jboolean    (*IsInstanceOf)(JNIEnv*, jobject, jclass);

4. 获取方法

本地C/C++代码中,可用同类对象jclass来获取该Java类的方法,主要包括获取类方法和获取静态方法。

函数 说明
GetMethodID 获取类方法
GetStaticMethodID 获取类的静态方法

对应的C++函数定义如下:

/**
 * 获取指定类的类方法
 * @param clazz Java类对象
 * @param name 方法名,必须为"utf-8"的字符串
 * @param sig 方法签名,必须为"utf-8"的字符串
 * @return 返回对应的方法ID,没有找到指定的方法,则返回NULL
 */
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)

/**
 * 获取指定类的静态方法
 * @param clazz Java类对象
 * @param name 方法名,必须为"utf-8"的字符串
 * @param sig 方法签名,必须为"utf-8"的字符串
 * @return 返回对应的方法ID,没有找到指定的方法,则返回NULL
 */
jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig)

对应的C函数定义为:

jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);

5. 类方法调用

Jni中本地函数中回调Java类方法通过调用CallMethod系列函数实现。CallMethod系列函数,根据传入参数的部分,分为CallMethod, CallMethodV和CallMethodA三类函数,参数区别如下:

函数 参数类型 参数说明
getMethod ... 可边长参数
getMethodV va_list va_list类型参数
getMethodA const jvalue* 数组形式的参数

以CallObjectMethod函数为列,看一下其函数原型。

// C 函数原型
jobject     (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
jobject     (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jobject     (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, const jvalue*);
// C++ 函数原型
jobject     CallObjectMethod(jobject, jmethodID, ...);
jobject     CallObjectMethodV(jobject, jmethodID, va_list);
jobject     CallObjectMethodA(jobject, jmethodID, const jvalue*);

类方法调用的CallMethod函数主要根据返回值类型的不同进行了分类,主要包括Object类型返回值的函数调用和基本数据类型返回值的函数调用。函数列表如下:

函数 返回值类型
CallObjectMethod
CallObjectMethodV
CallObjectMethodA
jobject
CallBooleanMethod
CallBooleanMethodV
CallBooleanMethodA
jboolean
CallByteMethod
CallByteMethodV
CallByteMethodA
jbyte
CallCharMethod
CallCharMethodV
CallCharMethodA
jchar
CallShortMethod
CallShortMethodV
CallShortMethodA
jshort
CallIntMethod
CallIntMethodV
CallIntMethodA
jint
CallLongMethod
CallLongMethodV
CallLongMethodA
jlong
CallFloatMethod
CallFloatMethodV
CallFloatMethodA
jfloat
CallDoubleMethod
CallDoubleMethodV
CallDoubleMethodA
jdouble
CallVoidMethod
CallVoidMethodV
CallVoidMethodA
void

6.类的静态方法调用

Jni中本地函数中回调Java类的静态方法的方式和访问类方法的类似。唯一不同的是,调用类的静态方法时不用传入Java类对象引用。CallStaticMethod系列函数列表如下:

函数 返回值类型
CallObjectStaticMethod
CallObjectStaticMethodV
CallObjectStaticMethodA
jobject
CallBooleanStaticMethod
CallBooleanStaticMethodV
CallBooleanStaticMethodA
jboolean
CallByteStaticMethod
CallByteStaticMethodV
CallByteStaticMethodA
jbyte
CallCharStaticMethod
CallCharStaticMethodV
CallCharStaticMethodA
jchar
CallShortStaticMethod
CallShortStaticMethodV
CallShortStaticMethodA
jshort
CallIntStaticMethod
CallIntStaticMethodV
CallIntStaticMethodA
jint
CallLongStaticMethod
CallLongStaticMethodV
CallLongStaticMethodA
jlong
CallFloatStaticMethod
CallFloatStaticMethodV
CallFloatStaticMethodA
jfloat
CallDoubleStaticMethod
CallDoubleStaticMethodV
CallDoubleStaticMethodA
jdouble
CallVoidStaticMethod
CallVoidStaticMethodV
CallVoidStaticMethodA
void

你可能感兴趣的:(Android JNI开发详解(6)-对象操作)