一、笔记
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
本文参考链接:https://www.cnblogs.com/hellokitty2/p/10391727.html