C++11 JNI开发中RAII的应用(三)--JavaClassMirror
2015-12-03 16:56
531 查看
以下是我以前写的将一个C++对象转成java对象的函数
如果这段代码被频繁调用,那么每次都要重复的去调用JNIEnv::FindClass,通过字符串去查找jobject,每次都要调用GetFieldID通过字符串查找获取FieldID。对是一个java class,这都是常量啊,为什么不可以一开始把这些值都记下来,每次使用时直接取这个值就行了?
于是,在前面《C++11 JNI开发中RAII的应用(一)–制作基础工具》和《C++11 JNI开发中RAII的应用(二)–JNI函数封装》两节的基础之上,我决定做一个JavaClassMirror类记录一个类的这些常量,用于后面的频繁调用。
有了这个类之后,比如我们可以像这样初始化
最开始那段代码
当然JavaClassMirror功能并不完整,并不能满足所有JNI开发的需要,只是在我的项目中这样做已经够了,自己完全可以按这个思路根据需要把更多的功能封装到这里。到这里关于C++11下JNI开发的相关内容就写完了。后续如果有更多的内容,还可能会继续补充。
toJCodeBean。
static jobject toJCodeBean(JNIEnv* env, const code_bean& bean) { auto code_bean_class =jni_utilits::raii_FindClass_LocalRef("Lnet/gdface/facedbsdk/local/CodeCacheManager$CodeBean;"); auto constructor = env->GetMethodID(code_bean_class.get(), "<init>", "()V"); auto obj = env->NewObject(code_bean_class.get(), constructor); auto field_id = env->GetFieldID(code_bean_class.get(), "id", "[B"); env->SetObjectField(obj, field_id, jni_utilits::tojbytearray((jbyte*) (((&bean.id))), (jsize) ((sizeof(bean.id)))).get()); auto field_code = env->GetFieldID(code_bean_class.get(), "code", "[B"); env->SetObjectField(obj, field_code, jni_utilits::tojbytearray((jbyte*) &(FACE_CODE_CONVERT(bean.code)), (jsize) sizeof(bean.code)).get()); auto field_imgMD5 = env->GetFieldID(code_bean_class.get(), "imgMD5", "Ljava/lang/String;"); env->SetObjectField(obj, field_imgMD5, MD5toJString(bean.imgMD5).get()); auto field_similarity = env->GetFieldID(code_bean_class.get(), "similarity", "F"); env->SetFloatField(code_bean_class.get(), field_similarity, (jfloat) (((bean.similarity)))); return obj; }
如果这段代码被频繁调用,那么每次都要重复的去调用JNIEnv::FindClass,通过字符串去查找jobject,每次都要调用GetFieldID通过字符串查找获取FieldID。对是一个java class,这都是常量啊,为什么不可以一开始把这些值都记下来,每次使用时直接取这个值就行了?
于是,在前面《C++11 JNI开发中RAII的应用(一)–制作基础工具》和《C++11 JNI开发中RAII的应用(二)–JNI函数封装》两节的基础之上,我决定做一个JavaClassMirror类记录一个类的这些常量,用于后面的频繁调用。
/* java类与C++类的镜像,便于操作java对象 */ class JavaClassMirror{ public: /* raii_var类变量,java class 的全局引用,JavaClassMirror析构的时候会自动释放全局引用*/ raii_var<jclass> javaclass; /* 类构造函数的 jmethodID */ jmethodID constructor; /* 方法名与jfieldID的映射,可以通过方法名查找到对应的jfieldID,不支持重载的多个方法*/ unordered_map<string,jfieldID> field; /* 根据类名,构造函数签名,以及 initializer_list提供的pair<string, string> * 初始化类,并将 */ JavaClassMirror(string canonicalName, std::pair<string, string> constr, std::initializer_list<std::pair<string, string> > field_signature) : javaclass(jni_utilits::raii_FindClass_GlobalRef(canonicalName.data())), constructor(jni_utilits::getJNIEnv()->GetMethodID(javaclass.get(), constr.first.data(), constr.second.data())) { auto env =jni_utilits::getJNIEnv(); //根据方法名和签名获取FieldID,加入field映射中 for (auto node : field_signature) { auto f = env->GetFieldID(javaclass.get(), node.first.data(), node.second.data()); assert(nullptr != f); field.emplace(node.first, f); } } JavaClassMirror(JavaClassMirror&&)=default; //根据不同的数据类型提供统一的SetField/GetField方法 template<typename T> typename std::enable_if<std::is_same<T,jdouble>::value>::type SetField(jobject obj, const char* name, T fieldObj) { jni_utilits::getJNIEnv()->SetDoubleField(obj, field.find(name)->second, fieldObj); } template<typename T> typename std::enable_if<std::is_same<T,jfloat>::value>::type SetField(jobject obj,const char* name,T fieldObj){ jni_utilits::getJNIEnv()->SetFloatField(obj,field.find(name)->second,fieldObj); } template<typename T> typename std::enable_if<std::is_same<T, jlong>::value>::type SetField(jobject obj, const char* name, T fieldObj) { jni_utilits::getJNIEnv()->SetLongField(obj, field.find(name)->second, fieldObj); } template<typename T> typename std::enable_if<std::is_same<T, jint>::value>::type SetField(jobject obj, const char* name, T fieldObj) { jni_utilits::getJNIEnv()->SetIntField(obj, field.find(name)->second, fieldObj); } template<typename T> typename std::enable_if<std::is_same<T, jshort>::value>::type SetField(jobject obj, const char* name, T fieldObj) { jni_utilits::getJNIEnv()->SetShortField(obj, field.find(name)->second, fieldObj); } template<typename T> typename std::enable_if<std::is_same<T, jchar>::value>::type SetField(jobject obj, const char* name, T fieldObj) { jni_utilits::getJNIEnv()->SetCharField(obj, field.find(name)->second, fieldObj); } template<typename T> typename std::enable_if<std::is_same<T, jbyte>::value>::type SetField(jobject obj, const char* name, T fieldObj) { jni_utilits::getJNIEnv()->SetByteField(obj, field.find(name)->second, fieldObj); } template<typename T> typename std::enable_if<std::is_same<T, jboolean>::value>::type SetField(jobject obj, const char* name, T fieldObj) { jni_utilits::getJNIEnv()->SetBooleanField(obj, field.find(name)->second, fieldObj); } template<typename T> typename std::enable_if<std::is_base_of<_jobject,typename std::remove_pointer<T>::type>::value>::type SetField(jobject obj, const char* name, T fieldObj) { jni_utilits::getJNIEnv()->SetObjectField(obj, field.find(name)->second, fieldObj); } template<typename T> typename std::enable_if<std::is_same<T,jdouble>::value,T>::type GetField(jobject obj,const char* name){ return jni_utilits::getJNIEnv()->GetDoubleField(obj,field.find(name)->second); } template<typename T> typename std::enable_if<std::is_same<T,jfloat>::value,T>::type GetField(jobject obj,const char* name){ return jni_utilits::getJNIEnv()->GetFloatField(obj,field.find(name)->second); } template<typename T> typename std::enable_if<std::is_same<T,jlong>::value,T>::type GetField(jobject obj,const char* name){ return jni_utilits::getJNIEnv()->GetLongField(obj,field.find(name)->second); } template<typename T> typename std::enable_if<std::is_same<T,jint>::value,T>::type GetField(jobject obj,const char* name){ return jni_utilits::getJNIEnv()->GetIntField(obj,field.find(name)->second); } template<typename T> typename std::enable_if<std::is_same<T,jshort>::value,T>::type GetField(jobject obj,const char* name){ return jni_utilits::getJNIEnv()->GetShortField(obj,field.find(name)->second); } template<typename T> typename std::enable_if<std::is_same<T,jchar>::value,T>::type GetField(jobject obj,const char* name){ return jni_utilits::getJNIEnv()->GetCharField(obj,field.find(name)->second); } template<typename T> typename std::enable_if<std::is_same<T,jbyte>::value,T>::type GetField(jobject obj,const char* name){ return jni_utilits::getJNIEnv()->GetByteField(obj,field.find(name)->second); } template<typename T> typename std::enable_if<std::is_same<T,jboolean>::value,T>::type GetField(jobject obj,const char* name){ return jni_utilits::getJNIEnv()->GetBooleanField(obj,field.find(name)->second); } template<typename T> typename std::enable_if<std::is_base_of<_jobject,typename std::remove_pointer<T>::type>::value,raii_var<T>>::type GetField(jobject obj,const char* name){ return jni_utilits::raii_GetObjectField<T>(obj,field.find(name)->second); }//返回raii_var封装的jobject };
有了这个类之后,比如我们可以像这样初始化
JavaClassMirror
JavaClassMirror mirror( "Lnet/gdface/facedbsdk/local/CodeCacheManager$CodeBean;",//类名 {"<init>", "()V"}, //构造函数 { {"id", "[B"}, {"code", "[B"}, {"imgMD5", "Ljava/lang/String;"}, {"similarity", "F"} }//成员变量名及类型签名 );
最开始那段代码
toJCodeBean就可以改成这样了,多么清楚简单。
raii_var<jobject> BeanUtilits::toJCodeBean(const code_bean& bean, JavaClassMirror& mirror) { auto var = jni_utilits::raii_NewObject(mirror.javaclass.get(), mirror.constructor); auto obj = *var; if (nullptr != obj) { mirror.SetField(obj, "id", MD5tojbyteArray(bean.id).get()); mirror.SetField(obj, "code",face_codetojbyteArray(FACE_CODE_CONVERT(bean.code)).get()); mirror.SetField(obj, "imgMD5", MD5toJString(bean.imgMD5).get()); mirror.SetField(obj, "similarity", (jfloat) (bean.similarity)); } return var; }
当然JavaClassMirror功能并不完整,并不能满足所有JNI开发的需要,只是在我的项目中这样做已经够了,自己完全可以按这个思路根据需要把更多的功能封装到这里。到这里关于C++11下JNI开发的相关内容就写完了。后续如果有更多的内容,还可能会继续补充。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序