之前的学习,知道了JNI可以让native代码访问基础类型和引用类型,本章节,我们要学习如果访问一个对象的字段(其实就是对象中的变量)和方法。此外,还将学习如何在native代码调用java编程语言实现的方法——这对回调函数,尤其有用。
class InstanceFieldAccess { private String s; private native void accessField(); public static void main(String args[]) { InstanceFieldAccess c = new InstanceFieldAccess(); c.s = "abc"; c.accessField(); System.out.println("In Java:"); System.out.println(" c.s = \"" + c.s + "\""); } static { System.loadLibrary("InstanceFieldAccess"); } }
JNIEXPORT void JNICALL Java_InstanceFieldAccess_accessField(JNIEnv *env, jobject obj) { jfieldID fid; /* store the field ID */ jstring jstr; const char *str; /* Get a reference to obj’s class */ jclass cls = (*env)->GetObjectClass(env, obj); printf("In C:\n"); /* Look for the instance field s in cls */ fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;"); if (fid == NULL) { return; /* failed to find the field */ } /* Read the instance field s */ jstr = (*env)->GetObjectField(env, obj, fid); str = (*env)->GetStringUTFChars(env, jstr, NULL); if (str == NULL) { return; /* out of memory */ } printf(" c.s = \"%s\"\n", str); (*env)->ReleaseStringUTFChars(env, jstr, str); /* Create a new string and overwrite the instance field */ jstr = (*env)->NewStringUTF(env, "123"); if (jstr == NULL) { return; /* out of memory */ } (*env)->SetObjectField(env, obj, fid, jstr); }
In C: c.s = "abc" In Java: c.s = "123"
fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String");
jstr = (*env)->GetObjectField(env, obj, fid);
javap -s InstanceFieldAccess
...s Ljava/lang/String;...
JNI字段描述符 | java编程语言 |
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
class StaticFielcdAccess { private static int si; private native void accessField(); public static void main(String args[]) { StaticFieldAccess c = new StaticFieldAccess(); StaticFieldAccess.si = 100; c.accessField(); System.out.println("In Java:"); System.out.println(" StaticFieldAccess.si = " + si); } static { System.loadLibrary("StaticFieldAccess"); } }
JNIEXPORT void JNICALL Java_StaticFieldAccess_accessField(JNIEnv *env, jobject obj) { jfieldID fid; /* store the field ID */ jint si; /* Get a reference to obj’s class */ jclass cls = (*env)->GetObjectClass(env, obj); printf("In C:\n"); /* Look for the static field si in cls */ fid = (*env)->GetStaticFieldID(env, cls, "si", "I"); if (fid == NULL) { return; /* field not found */ } /* Access the static field si */ si = (*env)->GetStaticIntField(env, cls, fid); printf(" StaticFieldAccess.si = %d\n", si); (*env)->SetStaticIntField(env, cls, fid, 200); }
In C: StaticFieldAccess.si = 100 In Java: StaticFieldAccess.si = 200
class InstanceMethodCall { private native void nativeMethod(); private void callback() { System.out.println("In Java"); } public static void main(String args[]) { InstanceMethodCall c = new InstanceMethodCall(); c.nativeMethod(); } static { System.loadLibrary("InstanceMethodCall"); } }
JNIEXPORT void JNICALL Java_InstanceMethodCall_nativeMethod(JNIEnv *env, jobject obj) { jclass cls = (*env)->GetObjectClass(env, obj); jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V"); if (mid == NULL) { return; /* method not found */ } printf("In C\n"); (*env)->CallVoidMethod(env, obj, mid); }
In C In Java
private native String getLine(String);
“(Ljava.lang.String;)Ljava.lang.String;”
public static void main(String[ ] args);
"(Ljava.lang.String;)V"
方法描述符 | java语言类型 |
"()Ljava/lang/String" | String f(); |
"(ILjava/lang/Class)J" | long f(int i, Class c); |
"([B)v" | void f(byte[ ] bytes); |
class StaticMethodCall { private native void nativeMethod(); private static void callback() { System.out.println("In Java"); } public static void main(String args[]) { StaticMethodCall c = new StaticMethodCall(); c.nativeMethod(); } static { System.loadLibrary("StaticMethodCall"); } }
JNIEXPORT void JNICALL Java_StaticMethodCall_nativeMethod(JNIEnv *env, jobject obj) { jclass cls = (*env)->GetObjectClass(env, obj); jmethodID mid = (*env)->GetStaticMethodID(env, cls, "callback", "()V"); if (mid == NULL) { return; /* method not found */ } printf("In C\n"); (*env)->CallStaticVoidMethod(env, cls, mid); }
In C In Java
jstring MyNewString(JNIEnv *env, jchar *chars, jint len) { jclass stringClass; jmethodID cid; jcharArray elemArr; jstring result; stringClass = (*env)->FindClass(env, "java/lang/String"); if (stringClass == NULL) { return NULL; /* exception thrown */ } /* Get the method ID for the String(char[]) constructor */ cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V"); if (cid == NULL) { return NULL; /* exception thrown */ } /* Create a char[] that holds the string characters */ elemArr = (*env)->NewCharArray(env, len); if (elemArr == NULL) { return NULL; /* exception thrown */ } (*env)->SetCharArrayRegion(env, elemArr, 0, len, chars); /* Construct a java.lang.String object */ result = (*env)->NewObject(env, stringClass, cid, elemArr); /* Free local references */ (*env)->DeleteLocalRef(env, elemArr); (*env)->DeleteLocalRef(env, stringClass); return result; }
result = (*env)->NewObject(env, stringClass, cid, elemArr);
result = (*env)->AllocObject(env, stringClass); if (result) { (*env)->CallNonvirtualVoidMethod(env, result, stringClass, cid, elemArr); /* we need to check for possible exceptions */ if ((*env)->ExceptionCheck(env)) { (*env)->DeleteLocalRef(env, result); result = NULL; } }
JNIEXPORT void JNICALL Java_InstanceFieldAccess_accessField(JNIEnv *env, jobject obj) { static jfieldID fid_s = NULL; /* cached field ID for s */ jclass cls = (*env)->GetObjectClass(env, obj); jstring jstr; const char *str; if (fid_s == NULL) { fid_s = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;"); if (fid_s == NULL) { return; /* exception already thrown */ } } printf("In C:\n"); jstr = (*env)->GetObjectField(env, obj, fid_s); str = (*env)->GetStringUTFChars(env, jstr, NULL); if (str == NULL) { return; /* out of memory */ } printf(" c.s = \"%s\"\n", str); (*env)->ReleaseStringUTFChars(env, jstr, str); jstr = (*env)->NewStringUTF(env, "123"); if (jstr == NULL) { return; /* out of memory */ } (*env)->SetObjectField(env, obj, fid_s, jstr); }
jstring MyNewString(JNIEnv *env, jchar *chars, jint len) { jclass stringClass; jcharArray elemArr; static jmethodID cid = NULL; jstring result; stringClass = (*env)->FindClass(env, "java/lang/String"); if (stringClass == NULL) { return NULL; /* exception thrown */ } /* Note that cid is a static variable */ if (cid == NULL) { /* Get the method ID for the String constructor */ cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V"); if (cid == NULL) { return NULL; /* exception thrown */ } } /* Create a char[] that holds the string characters */ elemArr = (*env)->NewCharArray(env, len); if (elemArr == NULL) { return NULL; /* exception thrown */ } (*env)->SetCharArrayRegion(env, elemArr, 0, len, chars); /* Construct a java.lang.String object */ result = (*env)->NewObject(env, stringClass, cid, elemArr); /* Free local references */ (*env)->DeleteLocalRef(env, elemArr); (*env)->DeleteLocalRef(env, stringClass); return result; }
class InstanceMethodCall { 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 = new InstanceMethodCall(); c.nativeMethod(); } static { System.loadLibrary("InstanceMethodCall"); initIDs(); } }
jmethodID MID_InstanceMethodCall_callback; 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); }