Native调用Java模块

JNI规范定义了一系列在Native代码中访问Java对象及其成员与方法的API。下面我们还是通过示例来具体讲解。首先,新建一个SayHello 的类,代码如下:

    package  com.example.hellojni;  
    public   class  SayHello {  
            public  String sayHelloFromJava(String nativeMsg) {  
                   String str = nativeMsg + " But shown in Java!" ;  
                   return  str;  
            }  
    }  

接下来要实现的就是在Native代码中调用这个 SayHello 类中的sayHelloFromJava方法。
 
一般来说,要在Native代码中访问Java对象,有如下几个步骤:
1.得到该Java对象的类定义。JNI定义了 jclass 这个类型来表示Java的类的定义,并提供了FindClass接口,根据类的完整的包路径即可得到其 jclass 。
2.根据 jclass 创建相应的对象实体,即 jobject 。在Java中,创建一个新对象只需要使用 new 关键字即可,但在Native代码中创建一个对象则需要两步:首先通过JNI接口GetMethodID得到该类的构造函数,然后利用NewObject接口构造出该类的一个实例对象。
3.访问 jobject 中的成员变量或方法。访问对象的方法是先得到方法的Method ID,然后使用Call< Type>Method 接口调用,这里Type对应相应方法的返回值——返回值为基本类型的都有相对应的接口,如CallIntMethod;其他的返回值(包括String) 则为CallObjectMethod。可以看出,创建对象实质上是调用对象的一个特殊方法,即构造函数。访问成员变量的步骤一样:首先 GetFieldID得到成员变量的ID,然后Get/Set< Type>Field读/写变量值。
 
上面概要介绍了从Native代码中访问Java对象的过程,下面我们结合示例来具体看一下。如下是调用sayHelloFromJava方法的Native代码:
    jstring helloFromJava( JNIEnv* env ) {  
           jstring str = NULL;  
           jclass clz = (*env)->FindClass(env, "com/example/hellojni/SayHello" );  
           jmethodID ctor = (*env)->GetMethodID(env, clz, "<init>" ,  "()V" );  
           jobject obj = (*env)->NewObject(env, clz, ctor);  
           jmethodID mid = (*env)->GetMethodID(env, clz, "sayHelloFromJava" ,  "(Ljava/lang/String;)Ljava/lang/String;" );  
           if  (mid) {  
                  jstring jmsg = (*env)->NewStringUTF(env, "I'm born in native." );  
                  str = (*env)->CallObjectMethod(env, obj, mid, jmsg);  
           }  
           return  str;  
    }  

可以看到,上述代码和前面讲到的步骤完全相符。这里提一下编程时要注意的要点:1、FindClass要写明Java类的完整包路径,并将 “.”以“/”替换;2、GetMethodID的第三个参数是方法名(对于构造函数一律用“<init>”表示),第四个参数是方法的“签 名”,需要用一个字符串序列表示方法的参数(依声明顺序)和返回值信息。由于篇幅所限,这里不再具体说明如何根据方法的声明构造相应的“签名”,请参考 JNI的相关文档。
 
关于上面谈到的步骤再补充说明一下:在JNI规范中,如上这种使用NewObject创建的对象实例被称为“Local Reference”,它仅在创建它的Native代码作用域内有效,因此应避免在作用域外使用该实例及任何指向它的指针。如果希望创建的对象实例在作用 域外也能使用,则需要使用NewGlobalRef接口将其提升为“Global Reference”——需要注意的是,当Global Reference不再使用后,需要显式的释放,以便通知JVM进行垃圾收集。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值