基本属于翻译。
首先必须存在之前传入的jobject obj,在根据 JNIEnv来获取jclass。
jclass cls = (*env)->GetObjectClass(env, obj);
当获取的jclass之后,也就知道该class的排布,之后开始获取相关的field。
jfieldID fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;");之后就是对于field的解析工作,这里这个是string,由于需要返回的是具体instance中的树枝,所以这里需要obj。jstring jstr = (*env)->GetObjectField(env, obj, fid);
如果是int等primitive参数,使用GetIntField系列的就好。
jni区域标识符
这个标识符用来描述区域的表示,已L开始,[代表数组, [I是int类型的数组,并且已分号结尾。
如果是类的应用,例如java.lang.String
书写为"Ljava/lang/String;"
具体的表格如下
Field Descriptor | Java Language Type |
---|---|
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
Field Descriptor | Java Language Type |
---|---|
"Ljava/lang/String;" | String |
"[I" | int[] |
"[Ljava/lang/Object;" |
可以利用工具javap来检查
javap -s -p YouClass
s Ljava/lang/String;
这里的函数的描述符。顺序是(param)returntype,其中参数和参数之间无需加任何符号。
Method Descriptor | Java Language Type |
---|---|
"()Ljava/lang/String;" | String f(); |
"(ILjava/lang/Class;)J" | long f(int i, Class c); |
"([B)V" | String(byte[] bytes); |
javap效果,如下
javap -s -p InstanceMethodCallprivate callback ()V public static main ([Ljava/lang/String;)V private native nativeMethod ()V
实例代码,如果在C中启动Runnable的run函数
jobject thd = ...; /* a java.lang.Thread instance */ jmethodID mid; jclass runnableIntf = (*env)->FindClass(env, "java/lang/Runnable"); /*或者这里可以使用GetObjectClass来获取jclass*/ if (runnableIntf == NULL) { ... /* error handling */ } mid = (*env)->GetMethodID(env, runnableIntf, "run", "()V"); if (mid == NULL) { ... /* error handling */ } (*env)->CallVoidMethod(env, thd, mid); ... /* check for possible exceptions */
C中回调java的函数
Call<type>Method----其中type代表该函数的返回值
每次都这作样的查找必然会损伤效率,这里缓存查找的结果
有2中方式,一种是在首次使用的时候,一种是在初始化的时候
1.首次使用很简单。
if(NULL = field_id) field_id = (*env)->GetXXXX
2.在构造中初始化其实是对于1方案的改进,因为1方案无法解决多线程重入判断的语句,而且还多了一条if语句,不符合追求最高性能的方法
classInstanceMethodCall
{ private static native void initIDs(); private native void nativeMethod(); private void callback() { System.out.println("In Java"); } public static void main(String args[]) {InstanceMethodCall
c = newInstanceMethodCall
(); c.nativeMethod(); } static { System.loadLibrary("InstanceMethodCall
"); initIDs(); } }其中 ,利用构造函数最先被调用的特点来初始化JNIEXPORT void JNICALL Java_InstanceMethodCall
_initIDs(JNIEnv *env, jclass cls) { MID_InstanceMethodCall
_callback = (*env)->GetMethodID(env, cls, "callback", "()V"); }JNIEXPORT void JNICALL Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj) { printf("In C/n"); (*env)->CallVoidMethod(env, obj, MID_InstanceMethodCall
_callback); }