`

让C++和Java相互调用(2)

 
阅读更多
http://chnic.iteye.com/blog/236248



3.getRamdomOrder()



这个方法会从backend得到一个随机的Order对象(抱歉这里“Random”拼错了),然后再调用java中相应的通知方法来通知foreground。getRamdomOrder方法没有参数,但是所对应的C++方法里却有两个参数,一定有人会不解。其实细心的朋友一定会发现,JNI里所有对应Java方法的C++ 方法都会比Java方法多两个参数,第一个参数是我们很熟悉的JNIEnv*指针,第二个参数有时是jobject有时是个jclass。针对这第二个参数在这里有必要多废话两句。



其实第二个参数传递的是包含了native本地方法的对象或者类对象,我们知道非静态的方法是属于某一个对象的,而静态方法是属于类对象的,所以静态方法可以被所有对象共享。有这个对象/类对象,我们就可以很方便的操作包含了native方法的对象的一些函数了。(这句话有点绕口,没看明白的建议多读两遍)。



废话完了言归正传,因为getRamdomOrder不是静态的,所以C++相对应的参数中传递来的是一个jobject对象。



Cpp代码 
jclass business_class = env->GetObjectClass(obj); 

jclass business_class = env->GetObjectClass(obj);

这一句不难理解,GetObjectClass方法可以得到一个对象的类对象,这句有点像Java中的Object.class。不熟悉的朋友建议再去看一下Java反射机制。接下来的几句C++代码应该在之前的方法1和方法2中都解释过。早backend端会发一个“消息”给foreground,之后new一个新的Order类出来。接下来的三句有必要再废话一下。



Cpp代码 
jfieldID amount_field = env->GetFieldID(order_class, "amount", "I");  
jint amount = env->GetIntField(order, amount_field);  
cout << "amount: " << amount << endl; 

jfieldID amount_field = env->GetFieldID(order_class, "amount", "I");
jint amount = env->GetIntField(order, amount_field);
cout << "amount: " << amount << endl;

之前我为Order这个Javabean的amount的属性设置了一个初始值为30,其实就是为了在这里演示如何在C++中拿一个Java对象的属性,拿的方法和我们之前说过的调用Java方法的程序差不多,也要先拿到一个jfieldID,之后调用Get<type>Field方法来取得某一个对象中的某一个属性的数值,最后cout把他打印出来。我们编写测试代码来看一下最终效果。



Java代码 
Business b = new Business();                   
Order o2 = b.getRamdomOrder();  
System.out.println(o2.getName()); 

Business b = new Business();
Order o2 = b.getRamdomOrder();
System.out.println(o2.getName());

运行上述的测试代码之后,控制台上打出了



Got a notification.
amount: 30
Fruit



和我们想要的结果是一样的,测试成功。



4.analyzeOrder(Order order)



这是一个静态方法,foreground会通过这个方法传一个Order的对象到backend去,然后再由CPP端进行“analyze”。在这里我们取出来传递过来的Order对象的name属性,然后打印到控制台上。因为这个方法是静态static方法,所以相对应的C++方法中的第二个参数也变成了jclass对象,也就是Business.class这个类对象。第三个参数是一个jobject对象,很明显就是我们传递过来的order对象。



前5句代码应该不难理解,就是调用getName这个方法,然后打印出来。因为JNI的API中并没有提供CallStringMethod这个方法,所以我们用CallObjectMethod这个方法来取得name这个字符串(String很明显也是一个Object),然后再转型成为jstring。也就是下面这句代码。



Cpp代码 
jstring name_str = static_cast<jstring>(env->CallObjectMethod(obj, getName_method)); 

jstring name_str = static_cast<jstring>(env->CallObjectMethod(obj, getName_method)); 
取到了name这个字符串之后cout打印出来,之后调用Business这个类对象中的静态方法notificationByStatic来通知foreground。调用的流程以及方法和非静态都是一样的,只不过注意JNI中调用静态方法的API所传递的一个参数是一个jclass而非jobject(这个也不难理解,因为静态方法是属于class类对象的)



还是编写测试代码测试这个方法



Java代码 
Business b = new Business();          
Order o = b.getOrder("Watermelom", 100);  
Business.analyzeOrder(o); 

Business b = new Business();
Order o = b.getOrder("Watermelom", 100);
Business.analyzeOrder(o); 
控制台上打印出



Name in Java_com_chnic_service_Business_analyzeOrder: Watermelom
Got a notification in a static method.



第一句是C++中cout打印出来的,第二句则是Java中的静态方法打印出来的,和我们想要的结果是一致的。





呼~好不容易介绍完了4个方法,最后总结一下吧。



JNI中所提供的API远远不止这4个方法中所使用的API。上面介绍的都是比较常用的,本人也不可能罗列出所有的API。
了解了JNI编程更加有利于深入了解Java中的反射机制,反之亦然。


因此如果有对JNI编程有兴趣或者有更深入的需要,可以参考一下sun的相关文档。在这里上传sun提供的JNI的API手册,还有上面例子中所用的演示代码给大家参考。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics