【混合编程jni 】第五篇之C++ 访问 Java代码
今天继续JNI的学习,因为是混合编程,所以在写的过程中需要进行交互
Java可以调用C++,C++也可以调用Java,
虽然作为Java程序很少写C++,但是既然是做JNI开发,就不得不了解下如果
在C++中访问Java的属性和方法,开始吧
访问属性
对象属性
// 获得方法的id
jfieldID GetFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
// 读取属性的值
NativeType Get<type>Field(JNIEnv *env, jobject obj,jfieldID fieldID);
// 设置属性的值
void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID,NativeType value);
返回类的实例(非静态)字段的字段 ID。该字段由其名称和签名指定。
访问器函数的GetField和SetField系列使用字段 ID 来检索对象字段。
来个例子
/* Get a reference to obj's class */
jclass cls = (*env)->GetObjectClass(env, obj); //第一步
printf("In C:\n");
/* Look for the instance field s in cls */
fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;"); //第二步
if (fid == NULL) {
return; /* failed to find the field */
}
/* Read the instance field s */
jstr = (*env)->NativeType Get<type>Field(JNIEnv *env, jobject obj,
jfieldID fieldID);(env, obj, fid); //第三步
访问静态属性
每一个对象的实例都有一个对象字段的复制;所有的对象共享一个类的静态字段。
静态属性在原来的方法基础上增加了static 的关键字
/* Get a reference to obj's class */
jclass cls = (*env)->GetObjectClass(env, obj);
printf("In C:\n");
/* Look for the static field si in cls */
fid = (*env)->GetStaticFieldID(env, cls, "si", "I");
if (fid == NULL) {
return; /* field not found */
}
/* Access the static field si */
si = (*env)->GetStaticIntField(env, cls, fid);
访问方法
// 获得对象id
jmethodID GetMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
// 调用方法
NativeType Call<type>Method(JNIEnv *env, jobject obj,jmethodID methodID, ...);
NativeType Call<type>MethodA(JNIEnv *env, jobject obj,jmethodID methodID, const jvalue *args);
NativeType Call<type>MethodV(JNIEnv *env, jobject obj,jmethodID methodID, va_list args);
注:三种调用方法的区别在于传递参数的区别,
第一个需要紧跟在methodId 之后
第二个要将参数放在args 数组中
第三个要将参数放在va-list中
// 调用对象方法
NativeType Call<type>Method(JNIEnv *env, jobject obj,jmethodID methodID, ...);
// 调用静态方法
NativeType CallStatic<type>Method(JNIEnv *env, jclass clazz,jmethodID methodID, ...);
// 调用父类对象方法
NativeType CallNonvirtual<type>Method(JNIEnv *env, jobject obj,jclass clazz, jmethodID methodID, ...);
CallNonvirtualMethod就能够对子类对象调用父类方法的功能。
如果想要调用一个对象的父类方法,而不是子类的这个方法的话,就可以使用CallNonvirtualMethod
使用方式:
首先取得父类及要调用的父类方法的jmethodID
然后传入到这个函数就能通过子类对象呼叫被覆写(override)的父方法
举个例子
// 获得对象的class
jclass clazz_TestNative = env->GetObjectClass(obj);
// 获得方法id
jmethodID id_max=env->GetMethodID(clazz_TestNative,"max","(DD)D");
// 调用方法
jdouble maxvalue =env->CallDoubleMethod(obj,
对象操作
获取类
// 使用绝对路径查找class
jclass FindClass(JNIEnv *env, const char *name);
// 根据对象查找class
jclass GetObjectClass(JNIEnv *env, jobject obj);
创建对象的方法
// 直接创建一个无参数的对象
jobject AllocObject(JNIEnv *env, jclass clazz);
// 调用有参的构造函数,在使用之前要先获得methodId
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里的instanceof ,判断是否是某个类的实例
jboolean IsInstanceOf(JNIEnv *env, jobject obj,jclass clazz);
// 判断是否是同一个对象引用
jboolean IsSameObject(JNIEnv *env, jobject ref1,jobject ref2);
总结
既然是混合编程,方法之间肯定有交互,
所以搞懂怎么访问对象的属性和方法,怎么调用方法是最基本的知识点
最后总结一下
想要访问属性 GetFieldID 想要获得属性的值 调用 GetField
想要调用方法 先要获得方法的的id
然后调用CallMethod
想要创建对象 AllocObject
回首看下上面的一些代码是不是和反射的使用很像?
- 点赞
- 收藏
- 关注作者
评论(0)