JNI学习笔记_C调用Java

一、笔记

1.C调用Java中的方法,参考jni.pdf pg97
可以参考博文:http://blog.csdn.net/lhzjj/article/details/26470999
步骤:
  a. 创建java虚拟机
  b. 获得class
  c. 实例化对象:获得构造方法(方法名为“<init>”),构造函数,调用方法
  d. 调用方法:又分为获得方法,构造参数,调用方法。(对于静态方法不需要实例化对象,可以没有步骤c)

2.C读取修改Java类的对象的成员属性
  a. 获取属性ID
  b. 读取/设置

3.之前都是java JNIDemo手动启动java虚拟机执行java程序,若C程序中调用了
java程序需要调用函数JNI_CreateJavaVM()来自动启动java虚拟机。

4.由Java程序的class文件获取(JNI)函数签名
$ javap -p -s JNIDemo.class

5.在/usr/lib下也可也grep字符串:/usr/lib$ grep JNI_CreateJavaVM -r ./

6.Java中参数中的String类对应到C中的jstring类型

7.运行时报找不到某个动态库,可以设置此库的路径到LD_LIBRARY_PATH

 

二、例子

Hello.java文件:

public class Hello {
    private String name;    /*C程序中调用SetObjectField()来设置*/
    private int age;        /*C程序中调用SetIntField()来设置*/
    
    public static void main(String args[]) {
        System.out.println("Hello, world!");
    }

    public int sayhello_to(String name) {
        System.out.println("Hello, "+name+"! I am "+this.name+", "+age+" years old.");       
        return 123;
    }

    public static void sayhello_to() {
    }
}

 

caller.c文件:

#include <stdio.h>  
#include <jni.h> 


jint create_vm(JavaVM** jvm, JNIEnv** env) 
{  
    JavaVMInitArgs args;  
    JavaVMOption options[1];  
    args.version = JNI_VERSION_1_6;  /*创建1.6版本的java虚拟机*/
    args.nOptions = 1;  
    options[0].optionString = "-Djava.class.path=./"; /*在当前目录下查找类*/
    args.options = options;  
    args.ignoreUnrecognized = JNI_FALSE;  
    return JNI_CreateJavaVM(jvm, (void **)env, &args);  
}  


int main(int argc, char **argv)
{
    JavaVM* jvm;
    JNIEnv* env;

    jclass cls;
    int ret = 0;

    jmethodID mid;
    jmethodID cid;

    jobject jobj;
    jstring jstr;

    jfieldID nameID;
    jfieldID ageID;

    int r;
        
    /* 1. create java virtual machine */
    if (create_vm(&jvm, &env)) {
        printf("can not create jvm\n");
        return -1;
    }

    /* 2. get class */
    cls = (*env)->FindClass(env, "Hello"); /*获取Hello类对象*/
    if (cls == NULL) {
        printf("can not find hello class\n");
        ret = -1;
        goto destroy;
    }

    /* 3. create object 
     * 3.1 get constructor method
     * 3.2 create parameters
     * 3.3 NewObject
     * 注意:调用类的静态成员方法的时候不需要实例化对象
     */

    /*<init>表示获取构造方法,构造函数的签名可以用javap -p -s Hello.class查看*/
    /* Get the method ID for the String constructor */
    cid = (*env)->GetMethodID(env, cls,    "<init>", "()V");
    if (cid == NULL) {
        ret = -1;
        printf("can not get constructor method");
        goto destroy;
    }

    /*调用类的构造函数实例化一个对象*/
    jobj = (*env)->NewObject(env, cls, cid);
    if (jobj == NULL) {
        ret = -1;
        printf("can not create object");
        goto destroy;
    }

    /* get/set field
     * 1. get field id
     * 2. get/set field
     */
    
    /*设置Hello类对象的name属性,arg4是属性的签名*/
    nameID = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
    if (nameID == NULL) {
        ret = -1;
        printf("can not get field name");
        goto destroy;
    }
    jstr = (*env)->NewStringUTF(env, "Bill");
    (*env)->SetObjectField(env, jobj, nameID, jstr); /*将name属性设置为“Bill”*/

    /*设置Hello类对象的age属性*/
    ageID = (*env)->GetFieldID(env, cls, "age", "I");
    if (ageID == NULL) {
        ret = -1;
        printf("can not get field age");
        goto destroy;
    }
    (*env)->SetIntField(env, jobj, ageID, 10);

    /* 4. call method
     * 4.1 get method
     * 4.2 create parameter
     * 4.3 call method
     */

    /*调用Java程序中的“sayhello_to”成员方法id*/
    mid = (*env)->GetMethodID(env, cls, "sayhello_to","(Ljava/lang/String;)I");
    if (mid == NULL) {
        ret = -1;
        printf("can not get method\n");
        goto destroy;
    }

    jstr = (*env)->NewStringUTF(env, "abcd@qq.com");

    /*调用Java程序中的“sayhello_to”成员方法并获取返回值。
     * 对比静态方法:
     * 这里是CallIntMethod()且其参数是对象
     * eg: static void main()是调用CallStaticVoidMethod()且参数是类
     */
    r = (*env)->CallIntMethod(env, jobj, mid, jstr);
    /*打印Java程序中的“sayhello_to”成员方法的返回值*/
    printf("ret = %d\n", r);

destroy:

    (*jvm)->DestroyJavaVM(jvm);
    return ret;
}

 

测试运行:

javac Hello.java

javap -p -s Hello.class //获取成员函数和成员属性的Signature,在C中调用Java函数或设置类的属性的时候使用。

gcc -I/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -o caller caller.c -L /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server -ljvm

export LD_LIBRARY_PATH=/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server
./caller

运行结果:

$ ./caller
Hello, abcd@qq.com! I am Bill, 10 years old.
ret = 123

 

 

TODO: 看 jni.pdf

posted on 2019-02-17 16:46  Hello-World3  阅读(283)  评论(0编辑  收藏  举报

导航