C++ ,JNI, Java 数据传递全解(二)

书接上回

我们如何将object类型的数据传递到java层

同样的,如果想要传递对象,则肯定需要知道这个对象在java中所在的类,java万物都离不开对象,而任何一个对象,总有一个对应的类来承载它。所以首先得到这个object的唯一class,那在C++中,就需要通过JNI找到该对象所在的类或者Bean,我们上文提到的第六个参数和第七个参数,他们分别是Route和EvStopoverInfo。那这两个对象在java中也是相应的bean,代码如下:

jclass cls = env->FindClass("com/faradayfuture/auto/routing/Route");
jclass m_route_class = reinterpret_cast<jclass>(env->NewGlobalRef(cls));

我们可以看到,首先Findclass 需要将类所在的路径交给它,C++会给我们返回一个jclass,然后我们通过NewGlobalRef 使我们所需要的jclass变成一个全局引用的变量。至此我们拿到了jclass。

拿到jclass之后,我们还需要一个参数,上篇讲过,需要一个ID,来确认我们要操作的唯一方法。既然我们是传递一个对象过去,那最简单最有效的实例化的方法,就是这个对象所在类的构造方法,Ok,我们来看代码:

jmethodId m_route_init = env->GetMethodID(m_route_class, "<init>", "(JJJ)V");

上方的代碼,讲一下参数,第一个是class,自不必说,第二个,是JNI固定的,代表调用的是该类的构造方法,那第三个参数,就不是固定的了。第三个参数,必须跟你构造函数中的参数类型进行匹配。而你java中定义的类对象,也需要跟你C++中要传递的object对象参数进行匹配,切记,C++中所有的跟对象相关的都需要转换成java所需要的。一定要追到源码底部,去看要传递的参数类型是什么,查找C++中参数的typedata是啥,如果是基础数据类型,那自不必说,按照我们上篇文章说的传入相对应的就好了,而对于一些特殊的,那我们就需要费点事了。例如,我们需要传入ArrayList或者Date类型的参数。那我们可能需要传入的参数可能就会如下代码:

"(ZIJLjava/util/List;)V"
"(ZJLjava/util/Date;DD)V"

拿到methodId之后,就需要将对象中的参数一起添加到一个jobject中,这样才能将该有的object数据传递出去。具体操作方式如下:

 //创建ArrayList对象,用于存储list数据
    jclass  list_jcs = jenv->FindClass("java/util/ArrayList");
    if(list_jcs == NULL) {
        LOG_INFO("ArrayList no find");
    }
    jmethodID list_init = jenv->GetMethodID(list_jcs,"<init>","()V");
    jobject list_obj = jenv->NewObject(list_jcs,list_init);
    jmethodID list_add = jenv->GetMethodID(list_jcs,"add","(Ljava/lang/Object;)Z");

解释下上方代码:

同样先找到List类,然后同步List的构造方法,获取methodId

然后创建一个List的object,并获得list的Add方法的唯一MethodId.

至此,List的object对象创建完毕,然后就需要将C++中的对象add到刚刚创建的List对象中

for(auto stopoverInfo : ev_range.stopovers) {
        jobject stopObject = jenv->NewObject(m_route_ev_stop_info_class,
                                             m_route_ev_stop_info_init,
                                             (jboolean)stopoverInfo.is_charging_station,
                                             (jlong)stopoverInfo.segment_index,
                                             (jlong)stopoverInfo.staying_time.count(),
                                             (jdouble)stopoverInfo.arrival_battery_level,
                                             (jdouble)stopoverInfo.departure_battery_level);
        jenv->CallBooleanMethod(list_obj,list_add,stopObject);
        jenv->DeleteLocalRef(stopObject);
    }

这段代码需要注意的是,1,NewObject是根据前面讲到的需要传递给Java的对象参数一致。2,调用Call方法,应该根据add方法来调用,因为Add方法返回时Boolean。3.循环末尾一定要加上Delete,否则很容易导致C++泄露。

Date当然,跟list是一致的。

最后,我们所有的参数都解决了,就需要做最后的工作了。

jenv->CallVoidMethod(m_router_obj, m_route_ev_station, (jlong)id, routeObj,routeEvRangeObj);

此处的参数,对应的是我们Java中最开始创建的方法参数,切记,丝毫不能差了,routObj和routeEvRangeObj 都是对象类型的参数,用刚才的方法,可以获取到。

最后,大家有不懂得,给我留言吧

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值