JNI实现源码分析【二 数据结构】
正文
在展開深入討論之前,先說一下Dalvik中和JNI相關的數據結構,是很有必要的。
在Object.h中定義了很多的數據結構:
0x01: 虛擬機中的對象
我們知道,Java是面向對象的,Java是運行在虛擬機里面的,即先通過編譯成字節碼(dalvik對應dex),虛擬機解析字節碼,構造出邏輯上相同的對象。 及虛擬機中的對象。
?a. struct Object
??根對象,就像我們知道,所有的對象都繼承Object一樣
?b. struct ClassObject
??虛擬機層面的類對象
?c. struct DataObject
??攜帶了數據的對象
?d. struct StringObject
??字符串對象
?e. struct ArrayObject
??數組對象
以上這幾個結構,就把Java里面的對象全部表述清楚了。
0x02: Dex相關的結構
下面的結構在解析Dex時會用到,同樣在JNI的實現中,也會用到,所以也說明一下。
?a. struct Field
??代表了類中的一個屬性,通常通過解析Dex中的field構造而來
?b. struct StaticField
??代表了類中的一個static屬性,通常通過解析Dex中的field構造而來
?c. struct InstField
??代表了類中的一個非static屬性,通常通過解析Dex中的field構造而來
?d. struct Method
??代表了類中的一個方法,通常通過解析Dex中的method構造而來
0x03: 實現JNI需要的數據結構
虛擬機在實現JNI時,需要一些特殊的結構。有管理虛擬機的,有JNI操作相關的。比如我們知道在JNI的API中就有兩個重要的結構:JavaVM,JNIEnv
?a. JavaVM
typedef const struct JNIInvokeInterface* JavaVM;??原來JavaVM只是一個JNIInvokeInterface類型的指針
?b. JavaVMExt
??在代碼中,我們經常看到JavaVMExt指針和JavaVM指針的互轉,所以順帶說一下,JavaVMExt可以說是JavaVM的擴展,實際上確實如此,可以看到它包含了更多的信息:
??它的第一個結構也是JNIInvokeInterface類型的指針,所以可以安全的和JavaVM互轉(當然只是對這個指針的使用的情況下)
?c. JNIInvokeInterface
struct JNIInvokeInterface {void* reserved0;void* reserved1;void* reserved2;jint (*DestroyJavaVM)(JavaVM*);jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);jint (*DetachCurrentThread)(JavaVM*);jint (*GetEnv)(JavaVM*, void**, jint);jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*); };??JNIInvokeInterface可以理解為函數表,其中包含了若干操作虛擬機的函數指針。
?d. JNIEnv
typedef const struct JNINativeInterface* JNIEnv;??JNIEnv是一個JNINativeInterface類型的指針
?e. JNIEnvExt
??同樣的,存在一個JNIEnv的擴展JNIEnvExt:
?f. JNINativeInterface
struct JNINativeInterface {void* reserved0;void* reserved1;void* reserved2;void* reserved3;jint (*GetVersion)(JNIEnv *);jclass (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,jsize);jclass (*FindClass)(JNIEnv*, const char*);jmethodID (*FromReflectedMethod)(JNIEnv*, jobject);jfieldID (*FromReflectedField)(JNIEnv*, jobject);/* spec doesn't show jboolean parameter */jobject (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);jclass (*GetSuperclass)(JNIEnv*, jclass);jboolean (*IsAssignableFrom)(JNIEnv*, jclass, jclass);/* spec doesn't show jboolean parameter */jobject (*ToReflectedField)(JNIEnv*, jclass, jfieldID, jboolean);jint (*Throw)(JNIEnv*, jthrowable);jint (*ThrowNew)(JNIEnv *, jclass, const char *);jthrowable (*ExceptionOccurred)(JNIEnv*);void (*ExceptionDescribe)(JNIEnv*);void (*ExceptionClear)(JNIEnv*);void (*FatalError)(JNIEnv*, const char*);jint (*PushLocalFrame)(JNIEnv*, jint);jobject (*PopLocalFrame)(JNIEnv*, jobject);jobject (*NewGlobalRef)(JNIEnv*, jobject);void (*DeleteGlobalRef)(JNIEnv*, jobject);void (*DeleteLocalRef)(JNIEnv*, jobject);jboolean (*IsSameObject)(JNIEnv*, jobject, jobject);jobject (*NewLocalRef)(JNIEnv*, jobject);jint (*EnsureLocalCapacity)(JNIEnv*, jint);jobject (*AllocObject)(JNIEnv*, jclass);jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...);jobject (*NewObjectV)(JNIEnv*, jclass, jmethodID, va_list);jobject (*NewObjectA)(JNIEnv*, jclass, jmethodID, jvalue*);jclass (*GetObjectClass)(JNIEnv*, jobject);jboolean (*IsInstanceOf)(JNIEnv*, jobject, jclass);jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list);jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list);jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list);jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list);jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list);jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...);jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list);jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...);jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list);jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jobject (*CallNonvirtualObjectMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jobject (*CallNonvirtualObjectMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jobject (*CallNonvirtualObjectMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jboolean (*CallNonvirtualBooleanMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jboolean (*CallNonvirtualBooleanMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jboolean (*CallNonvirtualBooleanMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jbyte (*CallNonvirtualByteMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jbyte (*CallNonvirtualByteMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jbyte (*CallNonvirtualByteMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jchar (*CallNonvirtualCharMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jchar (*CallNonvirtualCharMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jchar (*CallNonvirtualCharMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jshort (*CallNonvirtualShortMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jshort (*CallNonvirtualShortMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jshort (*CallNonvirtualShortMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jint (*CallNonvirtualIntMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jint (*CallNonvirtualIntMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jint (*CallNonvirtualIntMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jlong (*CallNonvirtualLongMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jlong (*CallNonvirtualLongMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jlong (*CallNonvirtualLongMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jfloat (*CallNonvirtualFloatMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jfloat (*CallNonvirtualFloatMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jfloat (*CallNonvirtualFloatMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jdouble (*CallNonvirtualDoubleMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jdouble (*CallNonvirtualDoubleMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jdouble (*CallNonvirtualDoubleMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);void (*CallNonvirtualVoidMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);void (*CallNonvirtualVoidMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);void (*CallNonvirtualVoidMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);jobject (*GetObjectField)(JNIEnv*, jobject, jfieldID);jboolean (*GetBooleanField)(JNIEnv*, jobject, jfieldID);jbyte (*GetByteField)(JNIEnv*, jobject, jfieldID);jchar (*GetCharField)(JNIEnv*, jobject, jfieldID);jshort (*GetShortField)(JNIEnv*, jobject, jfieldID);jint (*GetIntField)(JNIEnv*, jobject, jfieldID);jlong (*GetLongField)(JNIEnv*, jobject, jfieldID);jfloat (*GetFloatField)(JNIEnv*, jobject, jfieldID);jdouble (*GetDoubleField)(JNIEnv*, jobject, jfieldID);void (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);void (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean);void (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte);void (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar);void (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort);void (*SetIntField)(JNIEnv*, jobject, jfieldID, jint);void (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong);void (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat);void (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble);jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);jobject (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...);jobject (*CallStaticObjectMethodV)(JNIEnv*, jclass, jmethodID, va_list);jobject (*CallStaticObjectMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jboolean (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...);jboolean (*CallStaticBooleanMethodV)(JNIEnv*, jclass, jmethodID,va_list);jboolean (*CallStaticBooleanMethodA)(JNIEnv*, jclass, jmethodID,jvalue*);jbyte (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...);jbyte (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, va_list);jbyte (*CallStaticByteMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jchar (*CallStaticCharMethod)(JNIEnv*, jclass, jmethodID, ...);jchar (*CallStaticCharMethodV)(JNIEnv*, jclass, jmethodID, va_list);jchar (*CallStaticCharMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jshort (*CallStaticShortMethod)(JNIEnv*, jclass, jmethodID, ...);jshort (*CallStaticShortMethodV)(JNIEnv*, jclass, jmethodID, va_list);jshort (*CallStaticShortMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jint (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...);jint (*CallStaticIntMethodV)(JNIEnv*, jclass, jmethodID, va_list);jint (*CallStaticIntMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jlong (*CallStaticLongMethod)(JNIEnv*, jclass, jmethodID, ...);jlong (*CallStaticLongMethodV)(JNIEnv*, jclass, jmethodID, va_list);jlong (*CallStaticLongMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jfloat (*CallStaticFloatMethod)(JNIEnv*, jclass, jmethodID, ...);jfloat (*CallStaticFloatMethodV)(JNIEnv*, jclass, jmethodID, va_list);jfloat (*CallStaticFloatMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jdouble (*CallStaticDoubleMethod)(JNIEnv*, jclass, jmethodID, ...);jdouble (*CallStaticDoubleMethodV)(JNIEnv*, jclass, jmethodID, va_list);jdouble (*CallStaticDoubleMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);void (*CallStaticVoidMethodV)(JNIEnv*, jclass, jmethodID, va_list);void (*CallStaticVoidMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jfieldID (*GetStaticFieldID)(JNIEnv*, jclass, const char*,const char*);jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);jboolean (*GetStaticBooleanField)(JNIEnv*, jclass, jfieldID);jbyte (*GetStaticByteField)(JNIEnv*, jclass, jfieldID);jchar (*GetStaticCharField)(JNIEnv*, jclass, jfieldID);jshort (*GetStaticShortField)(JNIEnv*, jclass, jfieldID);jint (*GetStaticIntField)(JNIEnv*, jclass, jfieldID);jlong (*GetStaticLongField)(JNIEnv*, jclass, jfieldID);jfloat (*GetStaticFloatField)(JNIEnv*, jclass, jfieldID);jdouble (*GetStaticDoubleField)(JNIEnv*, jclass, jfieldID);void (*SetStaticObjectField)(JNIEnv*, jclass, jfieldID, jobject);void (*SetStaticBooleanField)(JNIEnv*, jclass, jfieldID, jboolean);void (*SetStaticByteField)(JNIEnv*, jclass, jfieldID, jbyte);void (*SetStaticCharField)(JNIEnv*, jclass, jfieldID, jchar);void (*SetStaticShortField)(JNIEnv*, jclass, jfieldID, jshort);void (*SetStaticIntField)(JNIEnv*, jclass, jfieldID, jint);void (*SetStaticLongField)(JNIEnv*, jclass, jfieldID, jlong);void (*SetStaticFloatField)(JNIEnv*, jclass, jfieldID, jfloat);void (*SetStaticDoubleField)(JNIEnv*, jclass, jfieldID, jdouble);jstring (*NewString)(JNIEnv*, const jchar*, jsize);jsize (*GetStringLength)(JNIEnv*, jstring);const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*);void (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*);jstring (*NewStringUTF)(JNIEnv*, const char*);jsize (*GetStringUTFLength)(JNIEnv*, jstring);/* JNI spec says this returns const jbyte*, but that's inconsistent */const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);void (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*);jsize (*GetArrayLength)(JNIEnv*, jarray);jobjectArray (*NewObjectArray)(JNIEnv*, jsize, jclass, jobject);jobject (*GetObjectArrayElement)(JNIEnv*, jobjectArray, jsize);void (*SetObjectArrayElement)(JNIEnv*, jobjectArray, jsize, jobject);jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize);jbyteArray (*NewByteArray)(JNIEnv*, jsize);jcharArray (*NewCharArray)(JNIEnv*, jsize);jshortArray (*NewShortArray)(JNIEnv*, jsize);jintArray (*NewIntArray)(JNIEnv*, jsize);jlongArray (*NewLongArray)(JNIEnv*, jsize);jfloatArray (*NewFloatArray)(JNIEnv*, jsize);jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize);jboolean* (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*);jbyte* (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*);jchar* (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*);jshort* (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*);jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);jlong* (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*);jfloat* (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*);jdouble* (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*);void (*ReleaseBooleanArrayElements)(JNIEnv*, jbooleanArray,jboolean*, jint);void (*ReleaseByteArrayElements)(JNIEnv*, jbyteArray,jbyte*, jint);void (*ReleaseCharArrayElements)(JNIEnv*, jcharArray,jchar*, jint);void (*ReleaseShortArrayElements)(JNIEnv*, jshortArray,jshort*, jint);void (*ReleaseIntArrayElements)(JNIEnv*, jintArray,jint*, jint);void (*ReleaseLongArrayElements)(JNIEnv*, jlongArray,jlong*, jint);void (*ReleaseFloatArrayElements)(JNIEnv*, jfloatArray,jfloat*, jint);void (*ReleaseDoubleArrayElements)(JNIEnv*, jdoubleArray,jdouble*, jint);void (*GetBooleanArrayRegion)(JNIEnv*, jbooleanArray,jsize, jsize, jboolean*);void (*GetByteArrayRegion)(JNIEnv*, jbyteArray,jsize, jsize, jbyte*);void (*GetCharArrayRegion)(JNIEnv*, jcharArray,jsize, jsize, jchar*);void (*GetShortArrayRegion)(JNIEnv*, jshortArray,jsize, jsize, jshort*);void (*GetIntArrayRegion)(JNIEnv*, jintArray,jsize, jsize, jint*);void (*GetLongArrayRegion)(JNIEnv*, jlongArray,jsize, jsize, jlong*);void (*GetFloatArrayRegion)(JNIEnv*, jfloatArray,jsize, jsize, jfloat*);void (*GetDoubleArrayRegion)(JNIEnv*, jdoubleArray,jsize, jsize, jdouble*);/* spec shows these without const; some jni.h do, some don't */void (*SetBooleanArrayRegion)(JNIEnv*, jbooleanArray,jsize, jsize, const jboolean*);void (*SetByteArrayRegion)(JNIEnv*, jbyteArray,jsize, jsize, const jbyte*);void (*SetCharArrayRegion)(JNIEnv*, jcharArray,jsize, jsize, const jchar*);void (*SetShortArrayRegion)(JNIEnv*, jshortArray,jsize, jsize, const jshort*);void (*SetIntArrayRegion)(JNIEnv*, jintArray,jsize, jsize, const jint*);void (*SetLongArrayRegion)(JNIEnv*, jlongArray,jsize, jsize, const jlong*);void (*SetFloatArrayRegion)(JNIEnv*, jfloatArray,jsize, jsize, const jfloat*);void (*SetDoubleArrayRegion)(JNIEnv*, jdoubleArray,jsize, jsize, const jdouble*);jint (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*,jint);jint (*UnregisterNatives)(JNIEnv*, jclass);jint (*MonitorEnter)(JNIEnv*, jobject);jint (*MonitorExit)(JNIEnv*, jobject);jint (*GetJavaVM)(JNIEnv*, JavaVM**);void (*GetStringRegion)(JNIEnv*, jstring, jsize, jsize, jchar*);void (*GetStringUTFRegion)(JNIEnv*, jstring, jsize, jsize, char*);void* (*GetPrimitiveArrayCritical)(JNIEnv*, jarray, jboolean*);void (*ReleasePrimitiveArrayCritical)(JNIEnv*, jarray, void*, jint);const jchar* (*GetStringCritical)(JNIEnv*, jstring, jboolean*);void (*ReleaseStringCritical)(JNIEnv*, jstring, const jchar*);jweak (*NewWeakGlobalRef)(JNIEnv*, jobject);void (*DeleteWeakGlobalRef)(JNIEnv*, jweak);jboolean (*ExceptionCheck)(JNIEnv*);jobject (*NewDirectByteBuffer)(JNIEnv*, void*, jlong);void* (*GetDirectBufferAddress)(JNIEnv*, jobject);jlong (*GetDirectBufferCapacity)(JNIEnv*, jobject);/* added in JNI 1.6 */jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject); };??JNINativeInterface可以理解為函數表,其中包含了JNI API提供的所有操作。
0x04: JNI參數傳遞的數據結構
方法調用少不了參數傳遞:入參和返回值,在JNI中,并不是直接將虛擬機中的Object暴露給API,而是使用了形如jobject這樣的結構,為何?主要還是安全方面的考慮,假如暴露了Object,那就可以在JNI中隨意調整Object的結構,這是框架所不愿意看到的。
一起看看JNI中的參數的數據結構:
typedef void* jobject; typedef jobject jclass; typedef jobject jstring; typedef jobject jarray; typedef jarray jobjectArray; typedef jarray jbooleanArray; typedef jarray jbyteArray; typedef jarray jcharArray; typedef jarray jshortArray; typedef jarray jintArray; typedef jarray jlongArray; typedef jarray jfloatArray; typedef jarray jdoubleArray; typedef jobject jthrowable; typedef jobject jweak;所以的參數看起來都是指針,但是需要注意,jobject并不是指向Object的指針,后面我們在講IndirectRefTable的時候會解釋。
而值得一提的是:
struct _jfieldID; /* opaque structure */ typedef struct _jfieldID* jfieldID; /* field IDs */struct _jmethodID; /* opaque structure */ typedef struct _jmethodID* jmethodID; /* method IDs */jfieldID和jmethodID 卻是指向真實Field和Method的指針。
作者:difcareer
鏈接:http://www.jianshu.com/p/e0d0c8923ae5
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
總結
以上是生活随笔為你收集整理的JNI实现源码分析【二 数据结构】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android逆向之旅---Native
- 下一篇: JNI实现源码分析【三 间接引用表】