• 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
    ");
            return -1;
        }
    
        /* 2. get class */
        cls = (*env)->FindClass(env, "Hello"); /*获取Hello类对象*/
        if (cls == NULL) {
            printf("can not find hello class
    ");
            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
    ");
            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
    ", 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

  • 相关阅读:
    Linux之Ubuntu添加/移除个人软件包存档的源[PPA,Personal Package Archives]
    [C++]Linux之头文件sys/types.h[/usr/include/sys]
    [C++]Linux之文件拷贝在系统调用和C库函数下的效率比较
    Linux之Ubuntu下安装屏幕录像软件(SimpleScreenRecorder)【摘抄】
    [C++]基于Curses库的实时系统监测可视化系统-2017-12-09 15-07-42
    [C++]Linux之虚拟文件系统[/proc]中关于CPU/内存/网络/内核等的一些概要性说明
    [C++]Linux之计算内存利用率与辨析
    [C++]Linux之网络实时检测功能
    [C++]Linux之C编程异常[true未定义解决方案]
    [C++]Linux之读取计算机网络数据[/proc/net/dev]
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10391727.html
Copyright © 2020-2023  润新知