JNI教程与技术手册
轉載:https://blog.csdn.net/shensky711/article/details/52806794
概述
對于JNI,有些童鞋在沒有接觸過的時候,可能會覺得比較復雜,但是其實當你真正去了解、去使用的時候,就會發現JNI的使用還是比較簡單的,JNI本身提供了一系列的API讓我們可以在native方法中操作java。JNI的使用無非也就是使用這些接口和java交互。這幾天在學習JNI接口的時候,發現網上搜索的JNI的中文雖然不少,但是很多都是零零碎碎的小例子,有一些官方文檔的翻譯,但要么是不全面,要么是資料比較舊了,干脆自己根據java native interface specification整理了一份技術資料。當然,很多時候看中文資料是詞不達意的,如果文中有疑問的地方歡迎指出,或者翻閱原文
首先,JNI是一個本地編程接口。它允許運行在Java虛擬機的Java代碼與用其他語言(如C,C++和匯編)編寫的庫交互
JNI最大的好處是JNI不受Java虛擬機實現方式的限制,因此,Java虛擬機廠商添加JNI的支持并不會影響虛擬機其他功能模塊。native代碼只需要編寫一遍,就可以在所有支持JNI的虛擬機上工作。
通過JNI,你可以在native代碼中:
- 創建、檢查或者更新java對象
- 調用java方法
- 捕捉和拋出異常
- 加載class和獲取class信息
- 運行時類型檢查
JNI接口函數和指針
本地代碼通過JNI函數(接口指針,接口指針是指針的指針)來訪問java VM.
JNI接口指針只在當前線程有效,因此在native方法中不要跨線程傳遞接口指針參數。native方法接收JNI接口指針參數,VM確保在同一個線程中調用native方法的時候,傳遞同一個接口指針給接口指針給native方法。然而,native方法可能在Java中的不同線程中調用,所以native方法接收到的接口指針可能就是不一樣的。
編譯、加載和鏈接本地方法
編譯
Java VM是多線程的,所以native libraries應該多線程編譯器來進行編譯和鏈接。例如使用Sun Studio compiler編譯器的時候,要為C++代碼添加-mt標記;使用GNU gcc compiler的時候,需添加-D_REENTRANT或-D_POSIX_C_SOURCE
加載
native庫通過System.loadLibrary方法進行加載。如:
package pkg;class Cls {native double f(int i, String s);static {System.loadLibrary("pkg_Cls");} }系統會對library名會進行轉換,在不同平臺上有不同的轉換方式,例如,Solaris系統轉換pkg_Cls為libpkg_Cls.so,而Win32系統轉換pkg_Cls為pkg_Cls.dll
鏈接
如果系統不支持動態鏈接,那么所有本地方法需要預鏈接到虛擬機,這種情況下,VM已經完成System.loadLibrary了。程序猿也可以調用JNI函數RegisterNatives()來注冊該類關聯的本地方法
Native Method 命令解析
一個本地方法名有以下幾個組成部分:
? 1.前綴Java_
? 2.完整雷鳴(類名中的.用_的代替)
? 3.下劃線_
? 4.方法名(方法名中的特殊字符需要轉義)
? 5.參數簽名(非必須,有重載方法的時候才需要),如果有重載的本地方法,需要再添加兩個下劃線__,然后在添加方法簽名(由java字段描述符描述,用_代替描述符中的包名分割/符,簽名中的特殊字符需要轉義)
Unicode轉義字符
| _0XXXX | 一個Unicode字符XXXX。注意小寫是用來表示非ascii Unicode字符, 如:_0abcd與_0ABCD不相同 |
| _1 | 字符_ |
| _2 | 參數簽名中的字符; |
| _3 | 參數簽名中的字符[ |
Java字段描述符
| Java類型 | 符號 |
| Boolean | Z |
| ·Byte | B |
| Char | C |
| Short | S |
| Int | I |
| Long | J |
| Float? | F |
| Double | D |
| Void | V |
| 數組 | [,如:int[]->[I, int[][]->[[I, Thread[]->[Ljava/lang/Thread; |
| objects | 以“L”開頭,以“;”結尾,中間是用"/"隔開的包及類名,比如:Ljava/lang/String;如果是嵌套類,則用$來表示嵌套。例如"(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z" |
舉例
package pkg;class Cls {//對應本地方法名: Java_pkg_Cls_f__ILjava_lang_String_2native double f(int i, String s);...}Native 方法參數
- JNI接口指針是native方法的第一個參數,JNI接口指針的類型是JNIEnv。
- 第二個參數取決于native method是否靜態方法,如果是非靜態方法,那么第二個參數是對對象的引用,如果是靜態方法,則第二個參數是對它的class類的引用
- 剩下的參數跟Java方法參數--對應
java對象引用
- 基本類型(如整型、字符等)在Java和native之間是采用值傳遞
- Java對象采用的是引用傳遞
虛擬機必須保持已傳遞給native的對象的引用,以使這些對象不被垃圾回收器回收。native code也必須有一種方法通知虛擬機它不再需要某個對象,并且垃圾收集器必須能夠將其回收。
全局引用、局部引用和弱全局應用
JNI中使用的引用可以劃分為三類:全局引用、局部引用和弱全局引用。局部引用在方法調用的時候有效,在方法調用結束之后會自動釋放。全局引用會一直可用,直到顯示地對其進行釋放。弱全局引用跟全局引用的區別是弱全局引用持有的java對象可以被VM進行回收,所以才是用弱全局引用前,我們需要對其進行檢測,看它對應的對象是否被回收了。
對象是作為局部引用傳遞給native方法的,所有通過JNIEnv方法(也就是JNI提供的API)返回的java對象都是局部引用。JNI允許程序從局部引用創建一個全局引用。JNIEnv的方法既可以接收全局引用也可以接收局部引用。一個native方法既可以返回局部引用也可以返回全局引用。
大多數情況下,在方法調用結束之后,我們依賴VMq幫我們釋放所有局部引用,但是以下幾種情況下,我們應該顯式地釋放局部引用:
- 方法中創建了一個比較大的java對象的,并持有其局部引用,使用完之后,如果接下來都不再需要使用了,如果仍然不對他進行釋放的話,在方法結束之前,這個對象都不會進行釋放,這樣會對資源造成浪費
- JNI會將創建的局部引用都存儲在一個局部引用表中,如果這個表超過了最大容量限制,就會造成局部引用表溢出,使程序崩潰。比如在一個循環中創建局部引用,最好在每一輪循環中釋放局部引用,否則隨著循環次數增加,很可能就內存溢出了
局部引用僅僅在其創建的線程內有效,native代碼不能跨線程傳遞局部引用。
訪問字段和方法
JNI允許native代碼訪問對象的成員以及調用它的方法,通過兩個步驟即可實現訪問,比如,我們需要調用cls中的f方法:
jmethodID mid = env->GetMethodID(cls, "f", "(ILjava/lang/String;)D"); //mid可以重復使用
jdouble result = env->CallDoubleMethod(obj, mid, 10, str);
但是需要注意的是,字段ID或方法ID并不能防止VM卸載該類。當類被卸載后,方法ID和字段ID將變成不可用的。因此,我們需要確保:
-持有class的引用,讓它不被卸載,或者
-重新獲取方法id或者字段id
程序錯誤檢測
JNI不對空指針或非法參數類型等錯誤進行檢測,因為:
- 檢查所有可能的錯誤會降低方法執行的性能
- 在很多時候,沒有足夠的運行時信息去進行檢測
程序員不得傳遞一個非法指針或者錯誤的類型給JNI函數,否則可能會導致系統異常或虛擬機泵擴
Java異常
JNI允許本地方法拋出處理任何異常,也可以處理Java中跑出的異常,剩下沒有處理的異常會繼續給VM處理
異常和錯誤碼
大多數情況下,JNI提供的方法通過返回錯誤碼或者拋出Java異常來處理錯誤,因此,程序中可以:
- 檢查JNI函數返回值
- 調用ExceptionOccurred()方法,獲取方法中拋出的異常
有兩種情況下,程序需要優先檢測java異常而不是先檢測返回碼
- 調用JNI調用Java方法的時候,需要ExceptionOccurred()檢測是否在Java方法中拋出了異常
- 一些訪問數組的方法,它不返回錯誤碼,但是會拋出ArrayIndexOutOfBoundsException或者ArrayStoreException異常
異常處理
有兩種方法可以在本地方法中處理異常
- 檢測到異常的時候立即返回,異常將會在調用該本地代碼的地方拋出
- 在本地方法中調用ExceptionClear()清除異常,處理接下來的邏輯
異常拋出時,本地方法需清除異常后,才能繼續調用其它JNI接口方法,有異常發生后,只有以下方法才能被安全調用:
? ExceptionOccurred()
? ExceptionDescribe()
? ExceptionClear()
? ExceptionCheck()
? ReleaseStringChars()
? ReleaseStringUTFChars()
? ReleaseStringCritical()
? Release<Type>ArrayElements()
? ReleasePrimitiveArrayCritical()
? DeleteLocalRef()
? DeleteGlobalRef()
? DeleteWeakGlobalRef()
? MonitorExit()
? PushLocalFrame()
? PopLocalFrame()
原始類型
| Java類型 | native類型 | 描述 |
| boolean | jboolean | unsigned 8 bits |
| byte | jbyte | signed 8 bits |
| char | jchar | unsigned 16 bits |
| short? | jshort | signed 16 bits |
| int | jint | signed 32 bits |
| long? | jlong | signed 64 bits |
| float? | jfloat | 32 bits |
| double | jdouble | 64 bits |
| void? | void | N/A |
JNI中還定義了以下兩個宏定義方便使用:
#define JNI_FALSE 0 #define JNI_TRUE 1引用類型
JNI為不同的java對象提供了不同的引用類型,JNI引用類型如下:
在c里面,所有JNI引用類型其實都是jobject
字段和方法ID
在C中,字段和方法ID是一個指向結構體的指針
struct _jfieldID; /* opaque structure*/ typedef struct _jfieldID *jfieldID; /*field IDs*/ struct _jmethodID; /*opaque structure*/ typedef struct _jmethodID *jmethodID; /*method IDs*/值類型
值類型jvalue是一個聯合體結構,定義如下:
typedef union jvalue {jboolean z;jbyte b;jchar c;jint i;jlong j;jfloat f;jdouble d;jobject l; } jvalue;簽名類型描述
請參考:java字段描述符?
如:
//方法簽名為:(ILjava/lang/String;[I)J long f (int n, String s, int[] arr);UTF-8字符
JNI的 UTF-8與標準的 UTF-8格式有兩個區別:
空字符(char)0使用雙字節格式編碼,而不是單字節編碼,所以Java虛擬機的UTF-8字符串不可能有嵌入的空值。
只使用單字節、雙字節和三字節編碼格式,不支持標準的四字節編碼,用two-times-three-byte格式代替
JNI接口函數
在下面的說明中,必須說明JNI函數必須接受一個非空對象,你必須保證傳入的參數不為空,JNI函數不需要再對它進行空指針判斷
返回碼說明
#define JNI_OK ? ? ? ? ?(0) ? ? ? ? /* no error */
#define JNI_ERR ? ? ? ? (-1) ? ? ? ?/* generic error */
#define JNI_EDETACHED ? (-2) ? ? ? ?/* thread detached from the VM */
#define JNI_EVERSION ? ?(-3) ? ? ? ?/* JNI version error */
#define JNI_COMMIT ? ? ?1 ? ? ? ? ? /* copy content, do not free buffer */
#define JNI_ABORT ? ? ? 2 ? ? ? ? ? /* free buffer w/o copying back */
?
接口詳細
? ? /**
? ? ?* 返回本地方法接口的版本
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?*
? ? ?* @return 高16位返回主版本號,低16位返回次版本號,如在JDK/JRE 1.6中,返回0x00010006。也有可能返回 JNI_EDETACHED 和 JNI_EVERSION 錯誤碼
? ? ?*/
? ? jint (*GetVersion)(JNIEnv *);
? ? /**
? ? ?* 從二進制的.class的數據緩沖區中加載類
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param name UTF8編碼的需要加載的類的名字
? ? ?* @param loader 類加載器
? ? ?* @param buf 包含.class字節碼的數組
? ? ?* @param bufLen 長度
? ? ?*
? ? ?* @return class對象或NULL
? ? ?*
? ? ?* @throws ClassFormatError 不是有效的class數據
? ? ?* @throws ClassCircularityError 類或接口是自身的父類或自身繼承了該接口
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?* @throws SecurityException 如果該類是屬于java包的
? ? ?*/
? ? jclass (*DefineClass)(JNIEnv *, const char *, jobject, const jbyte *, jsize);
? ? /**
? ? ?* 用于加載本地定義的類
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param name 完整的包名("/"代替".") 或 數組類型字段描述("["開頭,緊跟簽名描述),如"java/lang/String" for java.lang.String, "[Ljava/lang/Object;" for java.lang.Object[]
? ? ?*
? ? ?* @return class對象或NULL
? ? ?*
? ? ?* @throws ClassFormatError 不是有效的class數據
? ? ?* @throws ClassCircularityError 類或接口是自身的父類或自身繼承了該接口
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?* @throws NoClassDefFoundError 找不到name對應的class類
? ? ?*/
? ? jclass (*FindClass)(JNIEnv *, const char *);
? ? /**
? ? ?* 從java.lang.reflect.Method 或 java.lang.reflect.Constructor 獲取method ID
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param method java.lang.reflect.Method 或 java.lang.reflect.Constructor對象
? ? ?*
? ? ?* @return 方法ID
? ? ?*/
? ? jmethodID (*FromReflectedMethod)(JNIEnv *, jobject);
? ? /**
? ? ?* 從java.lang.reflect.Field獲取field ID
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param field java.lang.reflect.Field對象
? ? ?*
? ? ?* @return field ID
? ? ?*/
? ? jfieldID (*FromReflectedField)(JNIEnv *, jobject);
? ? /**
? ? ?* 從method ID獲取 java.lang.reflect.Method 或 java.lang.reflect.Constructor 對象
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param cls 該方法的類對象
? ? ?* @param methodID 方法ID
? ? ?* @param isStatic 是否靜態方法
? ? ?*
? ? ?* @return java.lang.reflect.Method 或 java.lang.reflect.Constructor 對象
? ? ?*
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jobject (*ToReflectedMethod)(JNIEnv *, jclass, jmethodID, jboolean);
? ? /**
? ? ?* 如果clazz不是class對象或接口,則返回該class的超類
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz class對象
? ? ?*
? ? ?* @return 返回輸入類的父類 或 NULL
? ? ?*/
? ? jclass (*GetSuperclass)(JNIEnv *, jclass);
? ? /**
? ? ?* class1是否可以安全地轉換為class2,以下三種情況會返回TRUE
? ? ?* 1. 當class1和class2是同一個java class的引用
? ? ?* 2. class1是class2的子類
? ? ?* 3. class2是class1的某個接口
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz1 class1
? ? ?* @param clazz2 class2
? ? ?*
? ? ?* @return JNI_TRUE or JNI_FALSE
? ? ?*/
? ? jboolean (*IsAssignableFrom)(JNIEnv *, jclass, jclass);
? ? /**
? ? ?* 根據 field ID 獲取 java.lang.reflect.Field 對象
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param cls 該方法的類對象
? ? ?* @param fieldID 字段ID
? ? ?* @param isStatic 是否靜態變量
? ? ?*
? ? ?* @return java.lang.reflect.Field 對象
? ? ?*
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jobject (*ToReflectedField)(JNIEnv *, jclass, jfieldID, jboolean);
? ? /**
? ? ?* 拋出異常
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj java.lang.Throwable 對象
? ? ?*
? ? ?* @return 0:成功, 負數:失敗
? ? ?*
? ? ?* @throws Throwable
? ? ?*/
? ? jint (*Throw)(JNIEnv *, jthrowable);
? ? /**
? ? ?* 根據clazz和message構造一個異常對象,并將它拋出
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz java.lang.Throwable的子類
? ? ?* @param message 錯誤信息
? ? ?*
? ? ?* @return 0:成功, 負數:失敗
? ? ?*
? ? ?* @throws Throwable
? ? ?*/
? ? jint (*ThrowNew)(JNIEnv *, jclass, const char *);
? ? /**
? ? ?* 判斷是否有異常拋出,在調用ExceptionClear()或java代碼處理了exception之前,都可以用這個方法判斷是否有異常
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?*
? ? ?* @return 異常對象 or NULL
? ? ?*/
? ? jthrowable (*ExceptionOccurred)(JNIEnv *);
? ? /**
? ? ?* 打印異常信息
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?*/
? ? void (*ExceptionDescribe)(JNIEnv *);
? ? /**
? ? ?* 清除所有已拋出的異常
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?*/
? ? void (*ExceptionClear)(JNIEnv *);
? ? /**
? ? ?* 拋出致命錯誤并且不希望虛擬機進行恢復。無返回值
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param msg 錯誤信息
? ? ?*/
? ? void (*FatalError)(JNIEnv *, const char *);
? ? /**
? ? ?* 創建一個新的本地引用幀
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param capacity 容量
? ? ?*
? ? ?* @return 0:成功,負數:失敗
? ? ?*
? ? ?* @throws OutOfMemoryError
? ? ?*/
? ? jint (*PushLocalFrame)(JNIEnv *, jint);
? ? /**
? ? ?* 彈出當前本地引用幀,釋放所有本地引用
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param result
? ? ?*
? ? ?* @return
? ? ?*/
? ? jobject (*PopLocalFrame)(JNIEnv *, jobject);
? ? /**
? ? ?* 為傳入的obj創建全局引用,obj可以是全局引用也可以是局部引用。全局引用需要調用DeleteGlobalRef來釋放
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj 全局或局部引用
? ? ?*
? ? ?* @return 全局引用 or NULL(內存不足)
? ? ?*/
? ? jobject (*NewGlobalRef)(JNIEnv *, jobject);
? ? /**
? ? ?* 釋放全局引用
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param globalRef 全局引用
? ? ?*/
? ? void (*DeleteGlobalRef)(JNIEnv *, jobject);
? ? /**
? ? ?* 釋放局部引用
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param localRef 局部引用
? ? ?*/
? ? void (*DeleteLocalRef)(JNIEnv *, jobject);
? ? /**
? ? ?* 判斷兩個引用是否同一java對象的引用
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param ref1 引用1
? ? ?* @param ref2 引用2
? ? ?*
? ? ?* @return JNI_TRUE:兩個引用指向同一個java對象
? ? ?*/
? ? jboolean (*IsSameObject)(JNIEnv *, jobject, jobject);
? ? /**
? ? ?* 為傳入的ref創建局部引用,ref可以是全局引用也可以是局部引用
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param ref 全局或局部引用
? ? ?*
? ? ?* @return 局部引用 or NULL
? ? ?*/
? ? jobject (*NewLocalRef)(JNIEnv *, jobject);
? ? /**
? ? ?* 確保當前線程可以創建capacity個局部引用。在進入本地方法時,VM確保可以可以創建最少16個局部引用
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param capacity 局部引用個數
? ? ?*
? ? ?* @return 0:成功,負數:失敗
? ? ?*
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jint (*EnsureLocalCapacity)(JNIEnv *, jint);
? ? /**
? ? ?* 創建一個新的java對象(不會調用對象的構造方法)
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz 非數組class對象
? ? ?*
? ? ?* @return java對象
? ? ?*
? ? ?* @throws InstantiationException clazz是一個接口或抽象類
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jobject (*AllocObject)(JNIEnv *, jclass);
? ? /**
? ? ?* 構造一個新的java對象,method ID指用以生成該類的構造方法,method ID必須是通過GetMethodID()獲得
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz 非數組class對象
? ? ?* @param ... 傳遞給構造方法的參數
? ? ?*
? ? ?* @return java對象 or NULL(對象構造失敗)
? ? ?*
? ? ?* @throws InstantiationException clazz是一個接口或抽象類
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jobject (*NewObject)(JNIEnv *, jclass, jmethodID, ...);
? ? /**
? ? ?* 構造一個新的java對象,method ID指用以生成該類的構造方法,method ID必須是通過GetMethodID()獲得
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz 非數組class對象
? ? ?* @param args va_list結構,里面有傳遞給構造方法的參數
? ? ?*
? ? ?* @return java對象 or NULL(對象構造失敗)
? ? ?*
? ? ?* @throws InstantiationException clazz是一個接口或抽象類
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jobject (*NewObjectV)(JNIEnv *, jclass, jmethodID, va_list);
? ? /**
? ? ?* 構造一個新的java對象,method ID指用以生成該類的構造方法,method ID必須是通過GetMethodID()獲得
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz 非數組class對象
? ? ?* @param args 參數數組,里面是傳遞給構造方法的參數
? ? ?*
? ? ?* @return java對象 or NULL(對象構造失敗)
? ? ?*
? ? ?* @throws InstantiationException clazz是一個接口或抽象類
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jobject (*NewObjectA)(JNIEnv *, jclass, jmethodID, jvalue *);
? ? /**
? ? ?* 返回對象對應的class對象
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj 非空java對象
? ? ?*
? ? ?* @return class對象
? ? ?*/
? ? jclass (*GetObjectClass)(JNIEnv *, jobject);
? ? /**
? ? ?* 判斷obj是否clazz的實例對象
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj java對象
? ? ?* @param clazz class對象
? ? ?*
? ? ?* @return
? ? ?*/
? ? jboolean (*IsInstanceOf)(JNIEnv *, jobject, jclass);
? ? /**
? ? ?* 返回非靜態方法的method ID
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz class對象
? ? ?* @param name 方法名
? ? ?* @param sig 方法簽名
? ? ?*
? ? ?* @return 方法ID or NULL
? ? ?*
? ? ?* @throws NoSuchMethodError 找不到對應的方法
? ? ?* @throws ExceptionInInitializerError class初始化失敗
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jmethodID (*GetMethodID)(JNIEnv *, jclass, const char *, const char *);
? ? /**
? ? ?* Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);調用參數放到可變參數中
? ? ?* Call<type>MethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);調用參數放入jvalue數組
? ? ?* Call<type>MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args);調用參數放入va_list結構中
? ? ?*
? ? ?* 以上三組調用接口都是根據 method ID調用java實例方法(非靜態方法)的接口,其中method ID是通過GetMethodID()獲取的
? ? ?* 當這些方法用于調用java對象的私有方法或構造函數時,method ID必須從obj的真實類獲取,而不應從其某個父類獲取
? ? ?* <type>是方法的返回類型,三類接口間唯一的區別是methodID參數之后調用參數的不同
? ? ?*
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj java對象
? ? ?* @param methodID 方法ID
? ? ?* @param args 調用參數
? ? ?*
? ? ?* @return java方法返回結果
? ? ?*
? ? ?* @throws java方法中可能拋出的異常
? ? ?*/
? ? 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 *);
? ? /**
? ? ?* CallNonvirtual<type>Method(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);調用參數放到可變參數中
? ? ?* CallNonvirtual<type>MethodA(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue *args);調用參數放入jvalue數組
? ? ?* CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args);調用參數放入va_list結構中
? ? ?*
? ? ?* 以上三組調用接口都是根據 method ID 和 class 調用java實例方法(非靜態方法)的接口,其中method ID是基于clazz通過GetMethodID()獲取的
? ? ?* <type>是方法的返回類型,三類接口間唯一的區別是methodID參數之后調用參數的不同
? ? ?* 注意,和Call<type>Method不同,如果子類重寫了父類的方法,Call<type>Method調用的是子類的方法,如果想調用父類的方法,
? ? ?* 則需要用CallNonvirtual<type>Method,這個方法可以傳入父類的class和父類的method id,從而達到調用父類方法的效果
? ? ?*
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz class對象
? ? ?* @param obj java對象
? ? ?* @param methodID 方法ID
? ? ?* @param args 調用參數
? ? ?*
? ? ?* @return java方法返回結果
? ? ?*
? ? ?* @throws java方法中可能拋出的異常
? ? ?*/
? ? 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 *);
? ? /**
? ? ?* 根據class對象獲取非靜態成員變量的field ID
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz class對象
? ? ?* @param name 變量名
? ? ?* @param sig 變量簽名
? ? ?*
? ? ?* @return field ID or NULL
? ? ?*
? ? ?* @throws NoSuchFieldError 找不到對應的變量ID
? ? ?* @throws ExceptionInInitializerError class初始化失敗
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jfieldID (*GetFieldID)(JNIEnv *, jclass, const char *, const char *);
? ? /**
? ? ?* 根據field id取出對象中相應的變量值,field Id通過GetFieldID()獲取
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj java對象
? ? ?* @param fieldID 有效的field id
? ? ?*
? ? ?* @return 相應的變量值
? ? ?*/
? ? 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);
? ? /**
? ? ?* 根據field id為相應的變量設置新的值,field Id通過GetFieldID()獲取
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj java對象
? ? ?* @param fieldID 有效的field id
? ? ?* @param value 要設置的值
? ? ?*/
? ? 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);
? ? /**
? ? ?* 返回靜態方法的method ID
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz class對象
? ? ?* @param name 方法名
? ? ?* @param sig 方法簽名
? ? ?*
? ? ?* @return 方法ID or NULL
? ? ?*
? ? ?* @throws NoSuchMethodError 找不到對應的方法
? ? ?* @throws ExceptionInInitializerError class初始化失敗
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jmethodID (*GetStaticMethodID)(JNIEnv *, jclass, const char *, const char *);
? ? /**
? ? ?* CallStatic<type>Method(JNIEnv *env, jclass clazz, jmethodID methodID, ...);調用參數放到可變參數中
? ? ?* CallStatic<type>MethodA(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);調用參數放入jvalue數組
? ? ?* CallStatic<type>MethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);調用參數放入va_list結構中
? ? ?*
? ? ?* 以上三組調用接口都是根據 method ID調用java靜態方法的接口,其中method ID是通過GetStaticMethodID()獲取的
? ? ?* method ID必須從clazz的真實類獲取,而不應從其某個父類獲取
? ? ?* <type>是方法的返回類型,三類接口間唯一的區別是methodID參數之后調用參數的不同
? ? ?*
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz class對象
? ? ?* @param methodID 方法ID
? ? ?* @param args 調用參數
? ? ?*
? ? ?* @return java方法返回結果
? ? ?*
? ? ?* @throws java方法中可能拋出的異常
? ? ?*/
? ? 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 *);
? ? /**
? ? ?* 根據class對象獲取靜態成員變量的field ID
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz class對象
? ? ?* @param name 變量名
? ? ?* @param sig 變量簽名
? ? ?*
? ? ?* @return field ID or NULL
? ? ?*
? ? ?* @throws NoSuchFieldError 找不到對應的變量ID
? ? ?* @throws ExceptionInInitializerError class初始化失敗
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jfieldID (*GetStaticFieldID)(JNIEnv *, jclass, const char *, const char *);
? ? /**
? ? ?* 根據field id取出對象中相應的變量值,field Id通過GetStaticFieldID()獲取
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz class對象
? ? ?* @param fieldID 有效的field id
? ? ?*
? ? ?* @return 相應的靜態變量值
? ? ?*/
? ? 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);
? ? /**
? ? ?* 根據field id為相應的靜態變量設置新的值,field Id通過GetStaticFieldID()獲取
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz class對象
? ? ?* @param fieldID 有效的field id
? ? ?* @param value 要設置的值
? ? ?*/
? ? 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);
? ? /**
? ? ?* 創建一個新的java.lang.String對象
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param unicodeChars 指向Unicode字符串的指針
? ? ?* @param len Unicode字符串的長度
? ? ?*
? ? ?* @return String對象 or NULL
? ? ?*
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jstring (*NewString)(JNIEnv *, const jchar *, jsize);
? ? /**
? ? ?* 返回java.lang.String的長度(Unicode字符數)
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param string String對象
? ? ?*
? ? ?* @return 長度
? ? ?*/
? ? jsize (*GetStringLength)(JNIEnv *, jstring);
? ? /**
? ? ?* 返回指向Unicode字符數組的指針
? ? ?* 該指針在調用ReleaseStringchars()前一直有效
? ? ?* 如果isCopy非空,則在復制完成后將*isCopy設為JNI_TRUE。否則設為JNI_FALSE
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param string String對象
? ? ?* @param isCopy 指向boolean的指針
? ? ?*
? ? ?* @return 指向字符串的指針 or NULL
? ? ?*/
? ? const jchar *(*GetStringChars)(JNIEnv *, jstring, jboolean *);
? ? /**
? ? ?* 通知VM無需再訪問chars
? ? ?* chars是一個指針,通過GetStringChars()
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param string String對象
? ? ?* @param chars 指向字符串的指針
? ? ?*/
? ? void (*ReleaseStringChars)(JNIEnv *, jstring, const jchar *);
? ? /**
? ? ?* 根據UTF-8編碼的字符數組創建一個新的java.lang.String對象
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param bytes 指向UTF-8字符串的指針
? ? ?*
? ? ?* @return String對象 or NULL
? ? ?*
? ? ?* @throws OutOfMemoryError 內存不足
? ? ?*/
? ? jstring (*NewStringUTF)(JNIEnv *, const char *);
? ? /**
? ? ?* 返回字符串以UTF-8為編碼的字節數
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param string String對象
? ? ?*
? ? ?* @return 字符串的UTF-8字節數
? ? ?*/
? ? jsize (*GetStringUTFLength)(JNIEnv *, jstring);
? ? /**
? ? ?* 返回指向UTF-8編碼字符數組的指針
? ? ?* 該指針在調用ReleaseStringUTFChars()前一直有效
? ? ?* 如果isCopy非空,則在復制完成后將*isCopy設為JNI_TRUE。否則設為JNI_FALSE
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param string String對象
? ? ?* @param isCopy 指向boolean的指針
? ? ?*
? ? ?* @return 指向字符串的指針 or NULL
? ? ?*/
? ? const char *(*GetStringUTFChars)(JNIEnv *, jstring, jboolean *);
? ? /**
? ? ?* 通知VM無需再訪問utf
? ? ?* utf是一個指針,通過GetStringUTFChars()
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param string String對象
? ? ?* @param utf 指向字符串的指針
? ? ?*/
? ? void (*ReleaseStringUTFChars)(JNIEnv *, jstring, const char *);
? ? /**
? ? ?* 獲取數組元素個數
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param array java數組對象
? ? ?*
? ? ?* @return 數組長度
? ? ?*/
? ? jsize (*GetArrayLength)(JNIEnv *, jarray);
? ? /**
? ? ?* 創建新的elementClass類型數組,所有元素初始值均設為initialElement
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param length 數組大小
? ? ?* @param elementClass 數組類型
? ? ?* @param initialElement 初始值
? ? ?*
? ? ?* @return 數組對象 or NULL
? ? ?*/
? ? jobjectArray (*NewObjectArray)(JNIEnv *, jsize, jclass, jobject);
? ? /**
? ? ?* 獲取對象數組中指定index的值
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param array java數組
? ? ?* @param index 索引
? ? ?*
? ? ?* @return 索引對象的對象
? ? ?*
? ? ?* @throws ArrayIndexOutOfBoundsException
? ? ?*/
? ? jobject (*GetObjectArrayElement)(JNIEnv *, jobjectArray, jsize);
? ? /**
? ? ?* 設置對象數組中指定index的值
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param array java數組
? ? ?* @param index 索引
? ? ?* @param value 新的值
? ? ?*
? ? ?* @throws ArrayIndexOutOfBoundsException
? ? ?*/
? ? void (*SetObjectArrayElement)(JNIEnv *, jobjectArray, jsize, jobject);
? ? /**
? ? ?* ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);
? ? ?* 創建基本類型數組對象
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param length 數組大小
? ? ?*
? ? ?* @return 數組對象 or NULL
? ? ?*/
? ? 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);
? ? /**
? ? ?* NativeType *Get<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, jboolean *isCopy);
? ? ?* 返回基本類型數組中的數據,通過返回的指針可以訪問這些數據,若虛擬機支持pinning,則指針指向原始數組,否則指向原始數組的拷貝
? ? ?* 返回的指針在Release<PrimitiveType>ArrayElements()調用前一直有效
? ? ?* 數組用使用結束后,調用Release<PrimitiveType>ArrayElements,并在調用參數中決定是否把修改提交給java
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param array java數組
? ? ?* @param isCopy 指向boolean的指針,若不為NULL,則執行了復制設為JNI_TRUE,否則設為JNI_FALSE
? ? ?*
? ? ?* @return 指向數組元素的指針 or NULL
? ? ?*/
? ? 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 *);
? ? /**
? ? ?* Release<PrimitiveType>ArrayElements
? ? ?* 通知VM不再需要訪問這些數組,根據mode參數的不同,將決定是否把數組的修改復制到源數組
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param array java數組對象
? ? ?* @param elems 指向數組元素的指針
? ? ?* @param mode 釋放模式,0:把數據復制回源數組并釋放elems緩沖區,JNI_COMMIT:把數據復制回源數組但不釋放elems緩沖區,JNI_ABORT:不把數據復制回源數組,釋放elems緩沖區
? ? ?*/
? ? 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 Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, NativeType *buf);
? ? ?* 把基本類型數組拷貝到buf中
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param array java數組
? ? ?* @param start 開始index
? ? ?* @param len 拷貝長度
? ? ?* @param buf 目標地址
? ? ?*
? ? ?* @throws ArrayIndexOutOfBoundsException
? ? ?*/
? ? 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 *);
? ? /**
? ? ?* void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, const NativeType *buf);
? ? ?* 把buf中的內容拷貝回數組中
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param array java數組
? ? ?* @param start 開始index
? ? ?* @param len 拷貝長度
? ? ?* @param buf 源數據
? ? ?*
? ? ?* @throws ArrayIndexOutOfBoundsException
? ? ?*/
? ? 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 *);
? ? /**
? ? ?* 為clazz類注冊本地方法
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz class對象
? ? ?* @param methods clazz類中的本地方法,指向方法數組
? ? ?* @param nMethods 本地方法個數
? ? ?*
? ? ?* @return 0:成功, 負數:失敗
? ? ?*
? ? ?* @throws NoSuchMethodError
? ? ?*/
? ? jint (*RegisterNatives)(JNIEnv *, jclass, const JNINativeMethod *, jint);
? ? /**
? ? ?* 取消clazz類本地方法的注冊
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param clazz class對象
? ? ?*
? ? ?* @return 0:成功, 負數:失敗
? ? ?*/
? ? jint (*UnregisterNatives)(JNIEnv *, jclass);
? ? /**
? ? ?* 進入與obj所引用的Java對象相關聯的監控,obj 必須為非空
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj java對象 或 class對象
? ? ?*
? ? ?* @return 0:成功, 負數:失敗
? ? ?*/
? ? jint (*MonitorEnter)(JNIEnv *, jobject);
? ? /**
? ? ?* 退出與obj所引用的Java對象相關聯的監控,obj 必須為非空
? ? ?* 當前線程必須是與obj所引用的Java對象相關聯的監控程序的所有者
? ? ?* 監控程序次數的計數器減 1。如果計數器的值變為 0,則釋放當前線程的監控程序
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj java對象 或 class對象
? ? ?*
? ? ?* @return 0:成功, 負數:失敗
? ? ?*/
? ? jint (*MonitorExit)(JNIEnv *, jobject);
? ? /**
? ? ?* 獲取當前線程關聯的Java VM接口
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param vm java VM接口指針
? ? ?*
? ? ?* @return 0:成功, 負數:失敗
? ? ?*/
? ? jint (*GetJavaVM)(JNIEnv *, JavaVM **);
? ? /**
? ? ?* 從start index開始,拷貝len個Unicode字符到buf
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param str string對象
? ? ?* @param start 開始index
? ? ?* @param len 拷貝長度
? ? ?* @param buf 目標地址
? ? ?*
? ? ?* @throws StringIndexOutOfBoundsException
? ? ?*/
? ? void (*GetStringRegion)(JNIEnv *, jstring, jsize, jsize, jchar *);
? ? /**
? ? ?* 從start index開始,取出len個Unicode字符轉換為UTF-8編碼后拷貝到buf
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param str string對象
? ? ?* @param start 開始index
? ? ?* @param len 拷貝長度
? ? ?* @param buf 目標地址
? ? ?*
? ? ?* @throws StringIndexOutOfBoundsException
? ? ?*/
? ? void (*GetStringUTFRegion)(JNIEnv *, jstring, jsize, jsize, char *);
? ? /**
? ? ?* 與Get/Release<primitivetype>ArrayElements方法非常相似,在這個方法中VM盡量返回指向原始數組的指針
? ? ?*
? ? ?* @since JDK/JRE 1.2
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param array java數組
? ? ?* @param isCopy 指向boolean的指針,若不為NULL,則執行了復制設為JNI_TRUE,否則設為JNI_FALSE
? ? ?*
? ? ?* @return 指向數組元素的指針 or NULL
? ? ?*/
? ? void *(*GetPrimitiveArrayCritical)(JNIEnv *, jarray, jboolean *);
? ? void (*ReleasePrimitiveArrayCritical)(JNIEnv *, jarray, void *, jint);
? ? /**
? ? ?* 與Get/ReleaseStringChars方法非常相似,在這個方法中VM盡量返回指向原始字符串的指針
? ? ?*
? ? ?* @since JDK/JRE 1.2
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param string String對象
? ? ?* @param isCopy 指向boolean的指針
? ? ?*
? ? ?* @return 指向字符串的指針 or NULL
? ? ?*/
? ? const jchar *(*GetStringCritical)(JNIEnv *, jstring, jboolean *);
? ? void (*ReleaseStringCritical)(JNIEnv *, jstring, const jchar *);
? ? /**
? ? ?* 為傳入的obj創建弱全局引用
? ? ?* 弱全局引用不會阻止VM釋放所引用的對象,程序中可以通過使用IsSameObject比較弱全局引用和NULL來確認所引用的對象是否被釋放
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj 全局或局部引用
? ? ?*
? ? ?* @return 弱全局引用 or NULL
? ? ?*/
? ? jweak (*NewWeakGlobalRef)(JNIEnv *, jobject);
? ? /**
? ? ?* 刪除弱全局引用
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj 弱全局引用
? ? ?*/
? ? void (*DeleteWeakGlobalRef)(JNIEnv *, jweak);
? ? /**
? ? ?* 判斷是否有未處理異常
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?*
? ? ?* @return JNI_TRUE表示有未處理異常,否則為JNI_FALSE
? ? ?*/
? ? jboolean (*ExceptionCheck)(JNIEnv *);
? ? /**
? ? ?* 創建并返回java.nio.ByteBuffer對象,該對象引用以address為開始地址,大小為capacity的內存塊
? ? ?*
? ? ?* @since JDK/JRE 1.4
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param address 開始地址
? ? ?* @param capacity 內存大小
? ? ?*
? ? ?* @return Jjava.nio.ByteBuffer or NULL
? ? ?*
? ? ?* @throws OutOfMemoryError
? ? ?*/
? ? jobject (*NewDirectByteBuffer)(JNIEnv *, void *, jlong);
? ? /**
? ? ?* 根據java.nio.ByteBuffer對象,獲取相應的內存數據并返回開始地址
? ? ?*
? ? ?* @since JDK/JRE 1.4
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param buf java.nio.ByteBuffer對象
? ? ?*
? ? ?* @return 數據的開始地址 or NULL
? ? ?*/
? ? void *(*GetDirectBufferAddress)(JNIEnv *, jobject);
? ? /**
? ? ?* 根據java.nio.ByteBuffer對象,獲取相應的內存數據的大小
? ? ?*
? ? ?* @since JDK/JRE 1.4
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param buf java.nio.ByteBuffer對象
? ? ?*
? ? ?* @return 數據大小 or -1
? ? ?*/
? ? jlong (*GetDirectBufferCapacity)(JNIEnv *, jobject);
? ? /**
? ? ?* 獲取java對象的引用類型,可能的返回值有:
? ? ?* JNIInvalidRefType
? ? ?* JNILocalRefType:局部引用
? ? ?* JNIGlobalRefType:全局引用
? ? ?* JNIWeakGlobalRefType :全局弱若引用
? ? ?*
? ? ?* @since JDK/JRE 1.6
? ? ?*
? ? ?* @param env JNI接口指針
? ? ?* @param obj java對象的引用
? ? ?*
? ? ?* @return 引用類型
? ? ?*/
? ? jobjectRefType (*GetObjectRefType)(JNIEnv *, jobject);
?
總結
以上是生活随笔為你收集整理的JNI教程与技术手册的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: lib和dll的区别、生成以及使用详解
- 下一篇: 手游引擎Unity和Cocos各有什么优