【混合编程jni 】第五篇之C++ 访问 Java代码

举报
香菜聊游戏 发表于 2022/06/26 21:27:54 2022/06/26
【摘要】 今天继续JNI的学习,因为是混合编程,所以在写的过程中需要进行交互Java可以调用C++,C++也可以调用Java,虽然作为Java程序很少写C++,但是既然是做JNI开发,就不得不了解下如果在C++中访问Java的属性和方法,开始吧访问属性对象属性// 获得方法的idjfieldID GetFieldID(JNIEnv *env, jclass clazz,const char *n...

今天继续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

回首看下上面的一些代码是不是和反射的使用很像?


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。