Jni 使用总结第二篇:c程序调用java

来源:互联网 发布:软件自动化测试工具 编辑:程序博客网 时间:2024/06/12 20:57

Jni使用总结二

c程序调用java

本文属于原创,转载请声明。

前言

众所周知,Java语言是将源代码编译成class文件的,并不能直接运行,需要在虚拟机中解析之后才能运行。个人理解jni的作用就是在我们的C程序中创建虚拟机,然后将java程序加载进来运行,根据我们的需求使用类的属性和方法。

1.java 程序

我们在c函数中将会对 age属性进行设置和调用sayhello方法并传入name
代码没啥可以说的,重点在c程序。

public class Hello{    private int age;    public static void main(String[] args) {        System.out.println("Hello world!");    }    public  int sayhello(String name){        System.out.println("Hello world!"+name);        System.out.println("Hello world!"+age);        return the data from java to c;    }    public void sayhello(){    }}

2.c 程序

a.创建虚拟机

写成函数的形式在main函数中调用。重点在与使用JNI_CreateJavaVM函数创建虚拟机

jint create_vm(JavaVM** jvm,JNIEnv** env) {          JavaVMInitArgs args;          JavaVMOption options[1];          args.version = JNI_VERSION_1_6;          args.nOptions = 1;          options[0].optionString = "-Djava.class.path=./";  //指明什么目录下查找类        args.options = options;          args.ignoreUnrecognized = JNI_FALSE;          return JNI_CreateJavaVM(jvm, (void **)env, &args);  }  
//main        JavaVM* jvm;    JNIEnv* env;    if(create_vm(&jvm,&env))    {        printf("create vm error\n");        return -1;    }

b.查找获取类

使用FindClass查找我们在c程序中要调用的类,第二个参数指定要查找的类名

jclass cls;cls = (*env)->FindClass(env, "Hello");if (cls == NULL) {    printf("can not find class\n");    ret=-1;    goto destroy;}

c.实例化对象

实例化对象包括以下几个小点:

i.获取构造方法ID
//获取构造方法ID        cid = (*env)->GetMethodID(env, cls,"<init>", "()V");    if (cid == NULL){        ret=-1;        printf("can not get the construction method\n");        goto destroy;    }

使用GetMethodID获取构造方法 :

第一个参数:环境env

第二个参数:上文查找到的类cls

第三个参数:默认<init>

第四个参数:JNI字段描述符通过命令获取

javap -p -s Hello

使用javap生成如下:Signature就是JNI字段描述符

public class Hello {  private int age;    Signature: I  public Hello();    Signature: ()V  public static void main(java.lang.String[]);    Signature: ([Ljava/lang/String;)V  public int sayhello(java.lang.String);    Signature: (Ljava/lang/String;)I  public void sayhello();    Signature: ()V}
ii.创建参数

: 如果调用没有参数的构造方法,此步骤可忽略。

iii.获取实例化对象

使用NewObject传入环境env,要实例化的类,类的构造方法ID,返回类的实例化对象。

//获取实例化对象    jobj= (*env)->NewObject(env, cls,cid);    if (cid == NULL){        ret=-1;        printf("can not create object\n");        goto destroy;    } 

d.设置类的属性

上文讲到要设置类的属性age的值,需要先通过GetFieldID找到属性的ID,才能使用SetIntField进行读取或者设置。

GetFieldID的用法类似GetMethodID

SetTypeField根据属性的类型修改Type的值。

//设置类的属性        int age;    jfid = (*env)->GetFieldID(env, cls, "age", "I");    if (jfid == NULL){        ret=-1;        printf("can not get field ID\n");        goto destroy;    }     age=22;    (*env)->SetIntField(env, jobj, jfid, age);//env,实例化对象,属性ID,要设置的内容

e.调用方法

i.获得调用方法的ID

//获得调用方法的ID    mid = (*env)->GetMethodID(env, cls, "sayhello","(Ljava/lang/String;)I");    if(mid==NULL)    {        printf("can not get the method\n");        goto destroy;    }

ii.调用方法

CallTypeMethod根据Java方法的返回值类型进行修改,参数分别是:
环境env;
实例化对象;
方法ID;
参数;

//调用方法    result = (*env)->CallIntMethod(env, jobj, mid, jstr);    printf("%d\n",result );

总结

上面两篇文章,介绍了java程序怎么调用c/c++库的函数;c程序怎么调用java方法;主要是从简单入手,希望起到抛砖引玉的作用。但文中对数据类型的转换没有详细的介绍,只是举例。期待第三篇对着方面进行详细的介绍。分享即所得。–manjia

原创粉丝点击