[JNI]开发之旅(8)传递参数给JNI函数

本节将介绍在JNI编程中如何传递参数和返回值。

首先要强调的是,native方法不但可以传递Java的基本类型做参数,还可以传递更复杂的类型,比如String,数组,甚至自定义的类。jni.h中定义了很多接口供我们操作。

其实在前面章节的例子中,我们已经使用到很多java传递参数给jni的例子,只是没有重点介绍,接下来会对传递几种基本类型参数,string,数组,java自定义对象这些参数介绍。

1. 基本类型的传递

实例1:传递int类型给JNI函数

java代码:


    public native int intMethod(int n);

JNI实现代码:


//传递int参数
extern "C"
jint Java_com_honjane_ndkdemo_JNIUtils_intMethod( JNIEnv* env, jobject jobj,jint num){

    return num*num;
}

注意:num没有经过转换,直接使用的。对的8中基本数据类型传递都可以直接使用,不需要再转换,而string,数组,对象就不能直接使用了,需要把jni数据结构转换成c,c++的数据结构才能操作。

结果:
传递num = 4;

I/main----intMethod: 16


实例2:传递boolean类型给JNI函数

java层:

    public native boolean booleanMethod(boolean bool);

JNI实现:


//传递布尔类型
extern "C"
jboolean Java_com_honjane_ndkdemo_JNIUtils_booleanMethod(JNIEnv* env,jobject jobj,jboolean flag){

    return !flag;
}

结果:
flag == true

I/main----booleanMethod: false

这里就介绍2个基本数据类型传参,其他几个类型,可以自行去实现。

2. String参数的传递

Java的String和C++的string是不能对等起来的,不能直接使用,需要通过一些函数转换。

实例3:传递String给JNI函数,把参数拼接到jni字符上,然后给java层使用

java代码:

    public native String stringMethod(String text);

JNI实现:

//传递string类型
extern "C"
jstring Java_com_honjane_ndkdemo_JNIUtils_stringMethod(JNIEnv* env,jobject jobj,jstring jstr){
    //将jstring类型转换成c++识别的char类型
    const char * str = env->GetStringUTFChars(jstr,0);
    char c[120] = "lily ";
    //调用c++拼接字符函数
    strcat(c,str);
    //释放
    env->ReleaseStringUTFChars(jstr,str);
    return env->NewStringUTF(c);
}

我们看到与实例1,2两个不一样,拿到jstring后,通过GetStringUTFChars把java层传过来的参数转换成char指针,然后才能操作。

结果:
text:hello

I/main----stringMethod: lily hello

3. 数组参数的传递

实例4:传递一个int数组给jni,然后实现数字元素求和

java代码:

    public native int intArrayMethod(int[] intArray);

JNI实现:


extern "C"
jint Java_com_honjane_ndkdemo_JNIUtils_intArrayMethod(JNIEnv* env,jobject jobj,jintArray jarr){
     jint len=0,sum=0;
     //获得数组长度
     len = env->GetArrayLength(jarr);
     //转换数组为int指针
     jint* body = env->GetIntArrayElements(jarr,0);
     //由于一些版本不兼容,i不定义在for循环中
     jint i=0;
     for(;i<len;i++){
        sum+=body[i];
     }
    return sum;
}

结果:
arr = {3,5,6,12,46,33};

I/main----intArrayMethod: 105

4. 自定义java对象参数的传递

实例5:传递复杂对象person,再jni函数中新构造一个person传回java层输出

定义Person

public class Person {
    private String name;
    private int age;


    public Person() {
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Person :{ name: "+name+",age: "+age+"}";
    }


}

java层native函数

    public native Person objectMethod(Person person);

JNI实现:


//传递person自定义对象给jni函数
extern "C"
jobject  Java_com_honjane_ndkdemo_JNIUtils_objectMethod(JNIEnv* env,jobject jobj,jobject jperson){
    jclass jcls = env->GetObjectClass(jperson);
//    jclass jcls =  env->FindClass("com/honjane/ndkdemo/model/Person"); //或反射得Person类引用

    if(jcls == NULL){
        return env->NewStringUTF("not find class");
    }
    //得到person对象的构造函数Person(int,string)
    jmethodID constrocMID = env->GetMethodID(jcls,"<init>","(ILjava/lang/String;)V");
    if(constrocMID == NULL){
        return env->NewStringUTF("not find constroc method");
    }

    jstring str = env->NewStringUTF("honjane");
     //构造一个对象,调用该类的构造函数,并且传递参数
    jobject new_ojb = env->NewObject(jcls,constrocMID,21,str); 

 return new_ojb;
}

输出结果:

I/main----objectMethod: Person :{ name:honjane ,age:21}

5. 集合参数的传递

实例6:传递复杂对象ArrayList,再jni函数中新构造一个ArrayList传回java层输出

java层

    public native ArrayList<Person> personArrayListMethod(ArrayList<Person> persons);

JNI实现:


//传递ArrayList<Person>集合给jni函数
extern "C"
jobject  Java_com_honjane_ndkdemo_JNIUtils_personArrayListMethod(JNIEnv* env,jobject jobj, jobject jlist){
    jclass jcls = env->GetObjectClass(jlist);
    if(jcls == NULL){
        return env->NewStringUTF("not find class");
    }
    jmethodID constrocMID = env->GetMethodID(jcls,"<init>","()V");
    if(constrocMID == NULL){
        return env->NewStringUTF("not find constroc method");
    }
    //创建一个Arraylist集合对象
    jobject list_obj = env->NewObject(jcls,constrocMID);
    //获取list的add方法id
    jmethodID list_add  = env->GetMethodID(jcls,"add","(Ljava/lang/Object;)Z");


    jclass jpersonCls = env->FindClass("com/honjane/ndkdemo/model/Person");

    jmethodID jpersonConstrocMID = env->GetMethodID(jpersonCls,"<init>","(ILjava/lang/String;)V");

   for(int i = 0 ; i < 3 ; i++)
       {
           jstring str = env->NewStringUTF("Native");
           //通过调用该对象的构造函数来new 一个 person实例
           jobject per_obj = env->NewObject(jpersonCls , jpersonConstrocMID , 20+i ,str);  //构造一个person对象
           //执行Arraylist类实例的add方法,添加一个person对象
           env->CallBooleanMethod(list_obj ,list_add, per_obj);
       }

 return list_obj;
}

其中构造器是通过init+一对尖括号表示,这句代码的意思是:获取Person(int,String)构造器的methodID


 env->GetMethodID(jpersonCls,"<init>","(ILjava/lang/String;)V");

输出结果:

    I/main----输出java list: [Person :{ name: lily,age: 10}, Person :{ name: lily,age: 11}, Person :{ name: lily,age: 12}]
    I/main----输出jni list: [Person :{ name: Native,age: 20}, Person :{ name: Native,age: 21}, Person :{ name: Native,age: 22}]

源码下载:https://github.com/honjane/JNIDemo

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值