JNI教程與技術(shù)手冊(cè)

概述

對(duì)于JNI冻璃,有些童鞋在沒(méi)有接觸過(guò)的時(shí)候,可能會(huì)覺(jué)得比較復(fù)雜债查,但是其實(shí)當(dāng)你真正去了解、去使用的時(shí)候瓜挽,就會(huì)發(fā)現(xiàn)JNI的使用還是比較簡(jiǎn)單的盹廷,JNI本身提供了一系列的API讓我們可以在native方法中操作java。JNI的使用無(wú)非也就是使用這些接口和java交互久橙。這幾天在學(xué)習(xí)JNI接口的時(shí)候俄占,發(fā)現(xiàn)網(wǎng)上搜索的JNI的中文雖然不少,但是很多都是零零碎碎的小例子剥汤,有一些官方文檔的翻譯颠放,但要么是不全面,要么是資料比較舊了吭敢,干脆自己根據(jù)java native interface specification整理了一份技術(shù)資料碰凶。當(dāng)然,很多時(shí)候看中文資料是詞不達(dá)意的鹿驼,如果文中有疑問(wèn)的地方歡迎指出欲低,或者翻閱原文

首先,JNI是一個(gè)本地編程接口畜晰。它允許運(yùn)行在Java虛擬機(jī)的Java代碼與用其他語(yǔ)言(如C,C++和匯編)編寫的庫(kù)交互
JNI最大的好處是JNI不受Java虛擬機(jī)實(shí)現(xiàn)方式的限制砾莱,因此,Java虛擬機(jī)廠商添加JNI的支持并不會(huì)影響虛擬機(jī)其它功能模塊凄鼻。native代碼只需要編寫一遍腊瑟,就可以在所有支持JNI的虛擬機(jī)上工作聚假。

通過(guò)JNI,你可以在native代碼中:

  • 創(chuàng)建闰非、檢查或者更新java對(duì)象
  • 調(diào)用java方法
  • 捕捉和拋出異常
  • 加載class和獲取class信息
  • 運(yùn)行時(shí)類型檢查

JNI接口函數(shù)和指針

本地代碼通過(guò)JNI函數(shù)(接口指針膘格,接口指針是指針的指針)來(lái)訪問(wèn)java VM。


2019-9-2-11-13-8.png

JNI接口指針只在當(dāng)前線程有效财松,因此在native方法中不要跨線程傳遞接口指針參數(shù)瘪贱。native方法接收J(rèn)NI接口指針參數(shù),VM確保在同一個(gè)線程中調(diào)用native方法的時(shí)候辆毡,傳遞同一個(gè)接口指針給接口指針給native方法菜秦。然而,native方法可能在Java中的不同線程中調(diào)用舶掖,所以native方法接收到的接口指針可能是不一樣的球昨。

編譯、加載和鏈接本地方法

編譯

Java VM是多線程的 眨攘,所以native libraries應(yīng)該用多線程編譯器來(lái)進(jìn)行編譯和鏈接褪尝。例如使用Sun Studio compiler編譯器的時(shí)候,要為c++代碼添加-mt標(biāo)記期犬;使用 GNU gcc compiler的時(shí)候,需添加-D_REENTRANT-D_POSIX_C_SOURCE

加載

native庫(kù)通過(guò)System.loadLibrary方法進(jìn)行加載避诽。如:

package pkg;  

class Cls { 

     native double f(int i, String s); 
     
     static { 
         System.loadLibrary("pkg_Cls"); 
     } 
} 

系統(tǒng)會(huì)對(duì)library名會(huì)進(jìn)行轉(zhuǎn)換龟虎,在不同平臺(tái)上有不同的轉(zhuǎn)換方式,例如沙庐,Solaris系統(tǒng)轉(zhuǎn)換pkg_Cls為libpkg_Cls.so鲤妥,而Win32系統(tǒng)轉(zhuǎn)換pkg_Cls為pkg_Cls.dll

鏈接

如果系統(tǒng)不支持動(dòng)態(tài)鏈接,那么所有本地方法需要預(yù)鏈接到虛擬機(jī)拱雏,這種情況下棉安,VM已經(jīng)完成System.loadLibrary了。程序員也可以調(diào)用JNI函數(shù)RegisterNatives()來(lái)注冊(cè)該類關(guān)聯(lián)的本地方法

Native Method命名解析

一個(gè)本地方法名有以下幾個(gè)組成部分:

  1. 前綴Java_
  2. 完整類名(類名中的._代替)
  3. 下劃線_
  4. 方法名(方法名中的特殊字符需要轉(zhuǎn)義)
  5. 參數(shù)簽名(非必須铸抑,有重載方法的時(shí)候才需要)贡耽,如果有重載的本地方法,需要再添加兩個(gè)下劃線__鹊汛,然后再添加方法簽名(由java字段描述符描述蒲赂,用_代替描述符中的包名分割/符,簽名中的特殊字符需要轉(zhuǎn)義)

Unicode 轉(zhuǎn)義字符

轉(zhuǎn)義符 說(shuō)明
_0XXXX 一個(gè)Unicode字符XXXX刁憋。注意小寫是用來(lái)表示非ascii Unicode字符, 如:_0abcd與_0ABCD不相同
_1 字符_
_2 參數(shù)簽名中的字符;
_3 參數(shù)簽名中的字符[

<span id="java_signatures"></span>

java字段描述符

Java 類型 符號(hào)
Boolean Z
Byte B
Char C
Short S
Int I
Long J
Float F
Double D
Void V
數(shù)組 [ , 如:int[]-> [I, int[][]-> [[I, Thread[]-> [Ljava/lang/Thread;
objects 以"L"開(kāi)頭滥嘴,以";"結(jié)尾,中間是用"/" 隔開(kāi)的包及類名至耻。比如:Ljava/lang/String;如果是嵌套類若皱,則用$來(lái)表示嵌套镊叁。例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"

舉例

package pkg;  

class Cls { 
    //對(duì)應(yīng)本地方法名:Java_pkg_Cls_f__ILjava_lang_String_2
    native double f(int i, String s); 

     ... 

} 

Native方法參數(shù)

  • JNI接口指針是native方法的第一個(gè)參數(shù),JNI接口指針的類型是JNIEnv走触。
  • 第二個(gè)參數(shù)取決于native method是否靜態(tài)方法晦譬,如果是非靜態(tài)方法,那么第二個(gè)參數(shù)是對(duì)對(duì)象的引用饺汹,如果是靜態(tài)方法蛔添,則第二個(gè)參數(shù)是對(duì)它的class類的引用
  • 剩下的參數(shù)跟Java方法參數(shù)一一對(duì)應(yīng)
package pkg;  

class Cls { 

     native double f(int i, String s); 

     ... 

}
//注意,c和c++在使用JNI接口的時(shí)候有點(diǎn)不一致兜辞,請(qǐng)仔細(xì)觀察通過(guò)env調(diào)用接口的調(diào)用方式
//C版本
jdouble Java_pkg_Cls_f__ILjava_lang_String_2 (
     JNIEnv *env,        /* interface pointer */
     jobject obj,        /* "this" pointer */
     jint i,             /* argument #1 */
     jstring s)          /* argument #2 */
{
     /* Obtain a C-copy of the Java string */
     const char *str = (*env)->GetStringUTFChars(env, s, 0);

     /* process the string */
     ...

     /* Now we are done with str */
     (*env)->ReleaseStringUTFChars(env, s, str);

     return ...
}

//C++版本
extern "C" /* specify the C calling convention */  
jdouble Java_pkg_Cls_f__ILjava_lang_String_2 ( 

     JNIEnv *env,        /* interface pointer */ 

     jobject obj,        /* "this" pointer */ 

     jint i,             /* argument #1 */ 

     jstring s)          /* argument #2 */ 

{ 

     const char *str = env->GetStringUTFChars(s, 0); 

     ... 

     env->ReleaseStringUTFChars(s, str); 

     return ... 

} 

java對(duì)象引用

  • 基本類型(如整型迎瞧,字符等)在Java和native之間是采用值傳遞
  • Java對(duì)象采用的是引用傳遞

虛擬機(jī)必須保持已傳遞給native的對(duì)象的引用,以使這些對(duì)象不被垃圾回收器回收逸吵。native code也必須有一種方法通知虛擬機(jī)它不再需要某個(gè)對(duì)象凶硅,并且垃圾收集器必須能夠?qū)⑵浠厥?/p>

全局引用、局部引用和弱全局引用

JNI中使用的引用可以劃分為三類:全局引用扫皱、局部引用弱全局引用足绅。局部引用在方法調(diào)用的時(shí)候有效,在方法調(diào)用結(jié)束之后會(huì)自動(dòng)釋放韩脑。全局引用會(huì)一直可用氢妈,直到顯式地對(duì)其進(jìn)行釋放。弱全局引用跟全局引用的區(qū)別是弱全局引用持有的java對(duì)象可以被VM進(jìn)行回收段多,所以才使用弱全局引用前首量,我們需要對(duì)其進(jìn)行檢測(cè),看它對(duì)應(yīng)的對(duì)象是否被回收了进苍。

對(duì)象是作為局部引用傳遞給native方法的加缘,所有通過(guò)JNIEnv方法(也就是JNI提供的API)返回的java對(duì)象都是局部引用。JNI允許程序從局部引用創(chuàng)建一個(gè)全局引用觉啊。JNIEnv的方法既可以接收全局引用也可以接收局部引用拣宏。一個(gè)native方法既可以返回局部引用也可以返回全局引用。

大多數(shù)情況下杠人,在方法調(diào)用結(jié)束之后勋乾,我們依賴VM去幫我們釋放所有局部引用,但是以下幾種情況下嗡善,我們應(yīng)該顯式地釋放局部引用:

  • 方法中創(chuàng)建了一個(gè)比較大的java對(duì)象的市俊,并持有其局部引用,使用完之后滤奈,如果接下來(lái)都不再需要使用了摆昧,如果仍然不對(duì)它進(jìn)行釋放的話,在方法結(jié)束之前蜒程,這個(gè)對(duì)象都不會(huì)進(jìn)行釋放绅你,這樣會(huì)對(duì)資源造成浪費(fèi)
  • JNI會(huì)將創(chuàng)建的局部引用都存儲(chǔ)在一個(gè)局部引用表中伺帘,如果這個(gè)表超過(guò)了最大容量限制,就會(huì)造成局部引用表溢出忌锯,使程序崩潰伪嫁。比如在一個(gè)循環(huán)中創(chuàng)建局部引用,最好在每一輪循環(huán)中釋放局部引用偶垮,否則隨著循環(huán)次數(shù)增加张咳,很可能就內(nèi)存溢出了

局部引用僅僅在其創(chuàng)建的線程內(nèi)有效,native代碼不能跨線程傳遞局部引用似舵。

訪問(wèn)字段和方法

JNI允許native代碼訪問(wèn)對(duì)象的成員以及調(diào)用它的方法脚猾,通過(guò)兩個(gè)步驟即可實(shí)現(xiàn)訪問(wèn),比如砚哗,我們需要調(diào)用cls中的f方法:

jmethodID mid = env->GetMethodID(cls, "f", "(ILjava/lang/String;)D");//mid可以重復(fù)使用
jdouble result = env->CallDoubleMethod(obj, mid, 10, str);

但是需要注意的是龙助,字段ID或方法ID并不能防止VM卸載該類。當(dāng)類被卸載后蛛芥,方法ID和字段ID將變成不可用的提鸟。因此,我們需要確保:

  • 持有class的引用仅淑,讓它不被卸載称勋,或者
  • 重新獲取方法id或者字段id

程序錯(cuò)誤檢測(cè)

JNI不對(duì)空指針或非法參數(shù)類型等錯(cuò)誤進(jìn)行檢測(cè),因?yàn)椋?/p>

  • 檢查所有可能的錯(cuò)誤會(huì)降低方法執(zhí)行的性能
  • 在很多時(shí)候涯竟,沒(méi)有足夠的運(yùn)行時(shí)信息去進(jìn)行檢測(cè)

程序員不得傳遞一個(gè)非法指針或者錯(cuò)誤的類型給JNI函數(shù)铣缠,否則可能會(huì)導(dǎo)致系統(tǒng)異常貨虛擬機(jī)崩潰

Java異常

JNI允許本地方法拋出處理任何異常,也可以處理Java中拋出的異常昆禽,剩下沒(méi)有處理的異常會(huì)繼續(xù)給VM處理

異常和錯(cuò)誤碼

大多數(shù)情況下,JNI提供的方法通過(guò)返回錯(cuò)誤碼或者拋出java異常來(lái)處理錯(cuò)誤蝇庭,因此醉鳖,程序中可以:

  • 檢查JNI函數(shù)返回值
  • 調(diào)用ExceptionOccurred()方法,獲取方法中拋出的異常

有兩種情況下哮内,程序需要優(yōu)先檢測(cè)java異常而不是先檢測(cè)返回碼

  • 通過(guò)JNI調(diào)用Java方法的時(shí)候盗棵,需要ExceptionOccurred()檢測(cè)是否在Java方法中拋出了異常
  • 一些訪問(wèn)數(shù)組的方法,它不返回錯(cuò)誤碼北发,但是會(huì)拋出ArrayIndexOutOfBoundsException 或者 ArrayStoreException異常

異常處理

有兩種方法可以在本地方法中處理異常

  • 檢測(cè)到異常的時(shí)候立即返回纹因,異常將會(huì)在調(diào)用該本地代碼的地方拋出
  • 在本地方法中調(diào)用ExceptionClear()清除異常,處理接下來(lái)的邏輯

異常拋出的時(shí)琳拨,本地方法需清除異常后瞭恰,才能繼續(xù)調(diào)用其他JNI接口方法,有異常發(fā)生后狱庇,只有以下方法才能被安全調(diào)用:

  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中還定義了以下兩個(gè)宏定義方便使用:

#define JNI_FALSE  0 
#define JNI_TRUE   1 

引用類型

JNI為不同的java對(duì)象提供了不同的引用類型惊畏,JNI引用類型如下:

2019-9-2-11-13-39.png

在c里面恶耽,所有JNI引用類型其實(shí)都是jobject

字段和方法ID

在C中,字段和方法ID是一個(gè)指向結(jié)構(gòu)體的指針

struct _jfieldID;                       /* opaque structure */
typedef struct _jfieldID* jfieldID;     /* field IDs */

struct _jmethodID;                      /* opaque structure */
typedef struct _jmethodID* jmethodID;   /* method IDs */

值類型

值類型jvalue是一個(gè)聯(lián)合體結(jié)構(gòu)颜启,定義如下:

typedef union jvalue {
    jboolean    z;
    jbyte       b;
    jchar       c;
    jshort      s;
    jint        i;
    jlong       j;
    jfloat      f;
    jdouble     d;
    jobject     l;
} jvalue;

簽名類型描述

請(qǐng)參考:java字段描述符
如:

//方法簽名為:(ILjava/lang/String;[I)J 
long f (int n, String s, int[] arr);

UTF-8字符

JNI的 UTF-8與標(biāo)準(zhǔn)的 UTF-8格式有兩個(gè)區(qū)別:

  • 空字符(char)0使用雙字節(jié)格式編碼偷俭,而不是單字節(jié)編碼,所以Java虛擬機(jī)的UTF-8字符串不可能有嵌入的空值缰盏。
  • 只使用單字節(jié)涌萤、雙字節(jié)和三字節(jié)編碼格式,不支持標(biāo)準(zhǔn)的四字節(jié)編碼口猜,用two-times-three-byte格式代替

JNI接口函數(shù)

在下面的說(shuō)明中负溪,必須說(shuō)明JNI函數(shù)必須接受一個(gè)非空對(duì)象,你必須保證傳入的參數(shù)不為空暮的,JNI函數(shù)不需要再對(duì)它進(jìn)行空指針判斷

返回碼說(shuō)明

#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 */

接口詳細(xì)

    /**
     * 返回本地方法接口的版本
     *
     * @param env JNI接口指針
     *
     * @return 高16位返回主版本號(hào)笙以,低16位返回次版本號(hào),如在JDK/JRE 1.6中,返回0x00010006冻辩。也有可能返回 JNI_EDETACHED 和 JNI_EVERSION 錯(cuò)誤碼
     */
    jint (*GetVersion)(JNIEnv *);


    /**
     * 從二進(jìn)制的.class的數(shù)據(jù)緩沖區(qū)中加載類
     *
     * @param env JNI接口指針
     * @param name UTF8編碼的需要加載的類的名字
     * @param loader 類加載器
     * @param buf 包含.class字節(jié)碼的數(shù)組
     * @param bufLen 長(zhǎng)度
     *
     * @return class對(duì)象或NULL
     *
     * @throws ClassFormatError 不是有效的class數(shù)據(jù)
     * @throws ClassCircularityError 類或接口是自身的父類或自身繼承了該接口
     * @throws OutOfMemoryError 內(nèi)存不足
     * @throws SecurityException 如果該類是屬于java包的
     */
    jclass (*DefineClass)(JNIEnv *, const char *, jobject, const jbyte *, jsize);


    /**
     * 用于加載本地定義的類
     *
     * @param env JNI接口指針
     * @param name 完整的包名("/"代替".") 或 數(shù)組類型字段描述("["開(kāi)頭猖腕,緊跟簽名描述),如"java/lang/String" for java.lang.String, "[Ljava/lang/Object;" for java.lang.Object[]
     *
     * @return class對(duì)象或NULL
     *
     * @throws ClassFormatError 不是有效的class數(shù)據(jù)
     * @throws ClassCircularityError 類或接口是自身的父類或自身繼承了該接口
     * @throws OutOfMemoryError 內(nèi)存不足
     * @throws NoClassDefFoundError 找不到name對(duì)應(yīng)的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對(duì)象
     *
     * @return 方法ID
     */
    jmethodID (*FromReflectedMethod)(JNIEnv *, jobject);


    /**
     * 從java.lang.reflect.Field獲取field ID
     *
     * @param env JNI接口指針
     * @param field java.lang.reflect.Field對(duì)象
     *
     * @return field ID
     */
    jfieldID (*FromReflectedField)(JNIEnv *, jobject);


    /**
     * 從method ID獲取 java.lang.reflect.Method 或 java.lang.reflect.Constructor 對(duì)象
     *
     * @param env JNI接口指針
     * @param cls 該方法的類對(duì)象
     * @param methodID 方法ID
     * @param isStatic 是否靜態(tài)方法
     *
     * @return java.lang.reflect.Method 或 java.lang.reflect.Constructor 對(duì)象
     *
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jobject (*ToReflectedMethod)(JNIEnv *, jclass, jmethodID, jboolean);


    /**
     * 如果clazz不是class對(duì)象或接口恨闪,則返回該class的超類
     *
     * @param env JNI接口指針
     * @param clazz class對(duì)象
     *
     * @return 返回輸入類的父類 或 NULL
     */
    jclass (*GetSuperclass)(JNIEnv *, jclass);


    /**
     * class1是否可以安全地轉(zhuǎn)換為class2倘感,以下三種情況會(huì)返回TRUE
     * 1. 當(dāng)class1和class2是同一個(gè)java class的引用
     * 2. class1是class2的子類
     * 3. class2是class1的某個(gè)接口
     *
     * @param env JNI接口指針
     * @param clazz1 class1
     * @param clazz2 class2
     *
     * @return JNI_TRUE or JNI_FALSE
     */
    jboolean (*IsAssignableFrom)(JNIEnv *, jclass, jclass);


    /**
     * 根據(jù) field ID 獲取 java.lang.reflect.Field 對(duì)象
     *
     * @param env JNI接口指針
     * @param cls 該方法的類對(duì)象
     * @param fieldID 字段ID
     * @param isStatic 是否靜態(tài)變量
     *
     * @return java.lang.reflect.Field 對(duì)象
     *
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jobject (*ToReflectedField)(JNIEnv *, jclass, jfieldID, jboolean);


    /**
     * 拋出異常
     *
     * @param env JNI接口指針
     * @param obj java.lang.Throwable 對(duì)象
     *
     * @return 0:成功, 負(fù)數(shù):失敗
     *
     * @throws Throwable
     */
    jint (*Throw)(JNIEnv *, jthrowable);


    /**
     * 根據(jù)clazz和message構(gòu)造一個(gè)異常對(duì)象咙咽,并將它拋出
     *
     * @param env JNI接口指針
     * @param clazz java.lang.Throwable的子類
     * @param message 錯(cuò)誤信息
     *
     * @return 0:成功老玛, 負(fù)數(shù):失敗
     *
     * @throws Throwable
     */
    jint (*ThrowNew)(JNIEnv *, jclass, const char *);


    /**
     * 判斷是否有異常拋出,在調(diào)用ExceptionClear()或java代碼處理了exception之前钧敞,都可以用這個(gè)方法判斷是否有異常
     *
     * @param env JNI接口指針
     *
     * @return 異常對(duì)象 or NULL
     */
    jthrowable (*ExceptionOccurred)(JNIEnv *);


    /**
     * 打印異常信息
     *
     * @param env JNI接口指針
     */
    void (*ExceptionDescribe)(JNIEnv *);


    /**
     * 清除所有已拋出的異常
     *
     * @param env JNI接口指針
     */
    void (*ExceptionClear)(JNIEnv *);


    /**
     * 拋出致命錯(cuò)誤并且不希望虛擬機(jī)進(jìn)行恢復(fù)蜡豹。無(wú)返回值
     *
     * @param env JNI接口指針
     * @param msg 錯(cuò)誤信息
     */
    void (*FatalError)(JNIEnv *, const char *);


    /**
     * 創(chuàng)建一個(gè)新的本地引用幀
     *
     * @param env JNI接口指針
     * @param capacity 容量
     *
     * @return 0:成功,負(fù)數(shù):失敗
     *
     * @throws OutOfMemoryError
     */
    jint (*PushLocalFrame)(JNIEnv *, jint);


    /**
     * 彈出當(dāng)前本地引用幀溉苛,釋放所有本地引用
     *
     * @param env JNI接口指針
     * @param result
     *
     * @return
     */
    jobject (*PopLocalFrame)(JNIEnv *, jobject);


    /**
     * 為傳入的obj創(chuàng)建全局引用镜廉,obj可以是全局引用也可以是局部引用。全局引用需要調(diào)用DeleteGlobalRef來(lái)釋放
     *
     * @param env JNI接口指針
     * @param obj 全局或局部引用
     *
     * @return 全局引用 or NULL(內(nèi)存不足)
     */
    jobject (*NewGlobalRef)(JNIEnv *, jobject);


    /**
     * 釋放全局引用
     *
     * @param env JNI接口指針
     * @param globalRef 全局引用
     */
    void (*DeleteGlobalRef)(JNIEnv *, jobject);


    /**
     * 釋放局部引用
     *
     * @param env JNI接口指針
     * @param localRef 局部引用
     */
    void (*DeleteLocalRef)(JNIEnv *, jobject);


    /**
     * 判斷兩個(gè)引用是否同一java對(duì)象的引用
     *
     * @param env JNI接口指針
     * @param ref1 引用1
     * @param ref2 引用2
     *
     * @return JNI_TRUE:兩個(gè)引用指向同一個(gè)java對(duì)象
     */
    jboolean (*IsSameObject)(JNIEnv *, jobject, jobject);


    /**
     * 為傳入的ref創(chuàng)建局部引用愚战,ref可以是全局引用也可以是局部引用
     *
     * @param env JNI接口指針
     * @param ref 全局或局部引用
     *
     * @return 局部引用 or NULL
     */
    jobject (*NewLocalRef)(JNIEnv *, jobject);


    /**
     * 確保當(dāng)前線程可以創(chuàng)建capacity個(gè)局部引用娇唯。在進(jìn)入本地方法時(shí),VM確奔帕幔可以可以創(chuàng)建最少16個(gè)局部引用
     *
     * @param env JNI接口指針
     * @param capacity 局部引用個(gè)數(shù)
     *
     * @return 0:成功塔插,負(fù)數(shù):失敗
     *
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jint (*EnsureLocalCapacity)(JNIEnv *, jint);


    /**
     * 創(chuàng)建一個(gè)新的java對(duì)象(不會(huì)調(diào)用對(duì)象的構(gòu)造方法)
     *
     * @param env JNI接口指針
     * @param clazz 非數(shù)組class對(duì)象
     *
     * @return java對(duì)象
     *
     * @throws InstantiationException clazz是一個(gè)接口或抽象類
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jobject (*AllocObject)(JNIEnv *, jclass);


    /**
     * 構(gòu)造一個(gè)新的java對(duì)象,method ID指用以生成該類的構(gòu)造方法拓哟,method ID必須是通過(guò)GetMethodID()獲得
     *
     * @param env JNI接口指針
     * @param clazz 非數(shù)組class對(duì)象
     * @param ... 傳遞給構(gòu)造方法的參數(shù)
     *
     * @return java對(duì)象 or NULL(對(duì)象構(gòu)造失敗)
     *
     * @throws InstantiationException clazz是一個(gè)接口或抽象類
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jobject (*NewObject)(JNIEnv *, jclass, jmethodID, ...);


    /**
     * 構(gòu)造一個(gè)新的java對(duì)象想许,method ID指用以生成該類的構(gòu)造方法,method ID必須是通過(guò)GetMethodID()獲得
     *
     * @param env JNI接口指針
     * @param clazz 非數(shù)組class對(duì)象
     * @param args va_list結(jié)構(gòu),里面有傳遞給構(gòu)造方法的參數(shù)
     *
     * @return java對(duì)象 or NULL(對(duì)象構(gòu)造失敗)
     *
     * @throws InstantiationException clazz是一個(gè)接口或抽象類
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jobject (*NewObjectV)(JNIEnv *, jclass, jmethodID, va_list);


    /**
     * 構(gòu)造一個(gè)新的java對(duì)象伸刃,method ID指用以生成該類的構(gòu)造方法谎砾,method ID必須是通過(guò)GetMethodID()獲得
     *
     * @param env JNI接口指針
     * @param clazz 非數(shù)組class對(duì)象
     * @param args 參數(shù)數(shù)組,里面是傳遞給構(gòu)造方法的參數(shù)
     *
     * @return java對(duì)象 or NULL(對(duì)象構(gòu)造失敗)
     *
     * @throws InstantiationException clazz是一個(gè)接口或抽象類
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jobject (*NewObjectA)(JNIEnv *, jclass, jmethodID, jvalue *);


    /**
     * 返回對(duì)象對(duì)應(yīng)的class對(duì)象
     *
     * @param env JNI接口指針
     * @param obj 非空java對(duì)象
     *
     * @return class對(duì)象
     */
    jclass (*GetObjectClass)(JNIEnv *, jobject);


    /**
     * 判斷obj是否clazz的實(shí)例對(duì)象
     *
     * @param env JNI接口指針
     * @param obj java對(duì)象
     * @param clazz class對(duì)象
     *
     * @return
     */
    jboolean (*IsInstanceOf)(JNIEnv *, jobject, jclass);


    /**
     * 返回非靜態(tài)方法的method ID
     *
     * @param env JNI接口指針
     * @param clazz class對(duì)象
     * @param name 方法名
     * @param sig 方法簽名
     *
     * @return 方法ID or NULL
     *
     * @throws NoSuchMethodError 找不到對(duì)應(yīng)的方法
     * @throws ExceptionInInitializerError class初始化失敗
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jmethodID (*GetMethodID)(JNIEnv *, jclass, const char *, const char *);


    /**
     * Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);調(diào)用參數(shù)放到可變參數(shù)中
     * Call<type>MethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);調(diào)用參數(shù)放入jvalue數(shù)組
     * Call<type>MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args);調(diào)用參數(shù)放入va_list結(jié)構(gòu)中
     *
     * 以上三組調(diào)用接口都是根據(jù) method ID調(diào)用java實(shí)例方法(非靜態(tài)方法)的接口捧颅,其中method ID是通過(guò)GetMethodID()獲取的
     * 當(dāng)這些方法用于調(diào)用java對(duì)象的私有方法或構(gòu)造函數(shù)時(shí)景图,method ID必須從obj的真實(shí)類獲取,而不應(yīng)從其某個(gè)父類獲取
     * <type>是方法的返回類型碉哑,三類接口間唯一的區(qū)別是methodID參數(shù)之后調(diào)用參數(shù)的不同
     *
     *
     * @param env JNI接口指針
     * @param obj java對(duì)象
     * @param methodID 方法ID
     * @param args 調(diào)用參數(shù)
     *
     * @return java方法返回結(jié)果
     *
     * @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, ...);調(diào)用參數(shù)放到可變參數(shù)中
     * CallNonvirtual<type>MethodA(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, const jvalue *args);調(diào)用參數(shù)放入jvalue數(shù)組
     * CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args);調(diào)用參數(shù)放入va_list結(jié)構(gòu)中
     *
     * 以上三組調(diào)用接口都是根據(jù) method ID 和 class 調(diào)用java實(shí)例方法(非靜態(tài)方法)的接口挚币,其中method ID是基于clazz通過(guò)GetMethodID()獲取的
     * <type>是方法的返回類型,三類接口間唯一的區(qū)別是methodID參數(shù)之后調(diào)用參數(shù)的不同
     * 注意扣典,和Call<type>Method不同妆毕,如果子類重寫了父類的方法,Call<type>Method調(diào)用的是子類的方法贮尖,如果想調(diào)用父類的方法笛粘,
     * 則需要用CallNonvirtual<type>Method,這個(gè)方法可以傳入父類的class和父類的method id湿硝,從而達(dá)到調(diào)用父類方法的效果
     *
     *
     * @param env JNI接口指針
     * @param clazz class對(duì)象
     * @param obj java對(duì)象
     * @param methodID 方法ID
     * @param args 調(diào)用參數(shù)
     *
     * @return java方法返回結(jié)果
     *
     * @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 *);


    /**
     * 根據(jù)class對(duì)象獲取非靜態(tài)成員變量的field ID
     *
     * @param env JNI接口指針
     * @param clazz class對(duì)象
     * @param name 變量名
     * @param sig 變量簽名
     *
     * @return field ID or NULL
     *
     * @throws NoSuchFieldError 找不到對(duì)應(yīng)的變量ID
     * @throws ExceptionInInitializerError class初始化失敗
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jfieldID (*GetFieldID)(JNIEnv *, jclass, const char *, const char *);


    /**
     * 根據(jù)field id取出對(duì)象中相應(yīng)的變量值薪前,field Id通過(guò)GetFieldID()獲取
     *
     * @param env JNI接口指針
     * @param obj java對(duì)象
     * @param fieldID 有效的field id
     *
     * @return 相應(yīng)的變量值
     */
    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);


    /**
     * 根據(jù)field id為相應(yīng)的變量設(shè)置新的值,field Id通過(guò)GetFieldID()獲取
     *
     * @param env JNI接口指針
     * @param obj java對(duì)象
     * @param fieldID 有效的field id
     * @param value 要設(shè)置的值
     */
    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);


    /**
     * 返回靜態(tài)方法的method ID
     *
     * @param env JNI接口指針
     * @param clazz class對(duì)象
     * @param name 方法名
     * @param sig 方法簽名
     *
     * @return 方法ID or NULL
     *
     * @throws NoSuchMethodError 找不到對(duì)應(yīng)的方法
     * @throws ExceptionInInitializerError class初始化失敗
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jmethodID (*GetStaticMethodID)(JNIEnv *, jclass, const char *, const char *);


    /**
     * CallStatic<type>Method(JNIEnv *env, jclass clazz, jmethodID methodID, ...);調(diào)用參數(shù)放到可變參數(shù)中
     * CallStatic<type>MethodA(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);調(diào)用參數(shù)放入jvalue數(shù)組
     * CallStatic<type>MethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);調(diào)用參數(shù)放入va_list結(jié)構(gòu)中
     *
     * 以上三組調(diào)用接口都是根據(jù) method ID調(diào)用java靜態(tài)方法的接口关斜,其中method ID是通過(guò)GetStaticMethodID()獲取的
     * method ID必須從clazz的真實(shí)類獲取示括,而不應(yīng)從其某個(gè)父類獲取
     * <type>是方法的返回類型,三類接口間唯一的區(qū)別是methodID參數(shù)之后調(diào)用參數(shù)的不同
     *
     *
     * @param env JNI接口指針
     * @param clazz class對(duì)象
     * @param methodID 方法ID
     * @param args 調(diào)用參數(shù)
     *
     * @return java方法返回結(jié)果
     *
     * @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 *);


    /**
     * 根據(jù)class對(duì)象獲取靜態(tài)成員變量的field ID
     *
     * @param env JNI接口指針
     * @param clazz class對(duì)象
     * @param name 變量名
     * @param sig 變量簽名
     *
     * @return field ID or NULL
     *
     * @throws NoSuchFieldError 找不到對(duì)應(yīng)的變量ID
     * @throws ExceptionInInitializerError class初始化失敗
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jfieldID (*GetStaticFieldID)(JNIEnv *, jclass, const char *, const char *);


    /**
     * 根據(jù)field id取出對(duì)象中相應(yīng)的變量值痢畜,field Id通過(guò)GetStaticFieldID()獲取
     *
     * @param env JNI接口指針
     * @param clazz class對(duì)象
     * @param fieldID 有效的field id
     *
     * @return 相應(yīng)的靜態(tài)變量值
     */
    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);


    /**
     * 根據(jù)field id為相應(yīng)的靜態(tài)變量設(shè)置新的值垛膝,field Id通過(guò)GetStaticFieldID()獲取
     *
     * @param env JNI接口指針
     * @param clazz class對(duì)象
     * @param fieldID 有效的field id
     * @param value 要設(shè)置的值
     */
    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);


    /**
     * 創(chuàng)建一個(gè)新的java.lang.String對(duì)象
     *
     * @param env JNI接口指針
     * @param unicodeChars 指向Unicode字符串的指針
     * @param len Unicode字符串的長(zhǎng)度
     *
     * @return String對(duì)象 or NULL
     *
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jstring (*NewString)(JNIEnv *, const jchar *, jsize);


    /**
     * 返回java.lang.String的長(zhǎng)度(Unicode字符數(shù))
     *
     * @param env JNI接口指針
     * @param string String對(duì)象
     *
     * @return 長(zhǎng)度
     */
    jsize (*GetStringLength)(JNIEnv *, jstring);


    /**
     * 返回指向Unicode字符數(shù)組的指針
     * 該指針在調(diào)用ReleaseStringchars()前一直有效
     * 如果isCopy非空,則在復(fù)制完成后將*isCopy設(shè)為JNI_TRUE丁稀。否則設(shè)為JNI_FALSE
     *
     * @param env JNI接口指針
     * @param string String對(duì)象
     * @param isCopy 指向boolean的指針
     *
     * @return 指向字符串的指針 or NULL
     */
    const jchar *(*GetStringChars)(JNIEnv *, jstring, jboolean *);


    /**
     * 通知VM無(wú)需再訪問(wèn)chars
     * chars是一個(gè)指針吼拥,通過(guò)GetStringChars()
     *
     * @param env JNI接口指針
     * @param string String對(duì)象
     * @param chars 指向字符串的指針
     */
    void (*ReleaseStringChars)(JNIEnv *, jstring, const jchar *);


    /**
     * 根據(jù)UTF-8編碼的字符數(shù)組創(chuàng)建一個(gè)新的java.lang.String對(duì)象
     *
     * @param env JNI接口指針
     * @param bytes 指向UTF-8字符串的指針
     *
     * @return String對(duì)象 or NULL
     *
     * @throws OutOfMemoryError 內(nèi)存不足
     */
    jstring (*NewStringUTF)(JNIEnv *, const char *);


    /**
     * 返回字符串以UTF-8為編碼的字節(jié)數(shù)
     *
     * @param env JNI接口指針
     * @param string String對(duì)象
     *
     * @return 字符串的UTF-8字節(jié)數(shù)
     */
    jsize (*GetStringUTFLength)(JNIEnv *, jstring);


    /**
     * 返回指向UTF-8編碼字符數(shù)組的指針
     * 該指針在調(diào)用ReleaseStringUTFChars()前一直有效
     * 如果isCopy非空,則在復(fù)制完成后將*isCopy設(shè)為JNI_TRUE线衫。否則設(shè)為JNI_FALSE
     *
     * @param env JNI接口指針
     * @param string String對(duì)象
     * @param isCopy 指向boolean的指針
     *
     * @return 指向字符串的指針 or NULL
     */
    const char *(*GetStringUTFChars)(JNIEnv *, jstring, jboolean *);


    /**
     * 通知VM無(wú)需再訪問(wèn)utf
     * utf是一個(gè)指針凿可,通過(guò)GetStringUTFChars()
     *
     * @param env JNI接口指針
     * @param string String對(duì)象
     * @param utf 指向字符串的指針
     */
    void (*ReleaseStringUTFChars)(JNIEnv *, jstring, const char *);


    /**
     * 獲取數(shù)組元素個(gè)數(shù)
     *
     * @param env JNI接口指針
     * @param array java數(shù)組對(duì)象
     *
     * @return 數(shù)組長(zhǎng)度
     */
    jsize (*GetArrayLength)(JNIEnv *, jarray);


    /**
     * 創(chuàng)建新的elementClass類型數(shù)組,所有元素初始值均設(shè)為initialElement
     *
     * @param env JNI接口指針
     * @param length 數(shù)組大小
     * @param elementClass 數(shù)組類型
     * @param initialElement 初始值
     *
     * @return 數(shù)組對(duì)象 or NULL
     */
    jobjectArray (*NewObjectArray)(JNIEnv *, jsize, jclass, jobject);


    /**
     * 獲取對(duì)象數(shù)組中指定index的值
     *
     * @param env JNI接口指針
     * @param array java數(shù)組
     * @param index 索引
     *
     * @return 索引對(duì)象的對(duì)象
     *
     * @throws ArrayIndexOutOfBoundsException
     */
    jobject (*GetObjectArrayElement)(JNIEnv *, jobjectArray, jsize);


    /**
     * 設(shè)置對(duì)象數(shù)組中指定index的值
     *
     * @param env JNI接口指針
     * @param array java數(shù)組
     * @param index 索引
     * @param value 新的值
     *
     * @throws ArrayIndexOutOfBoundsException
     */
    void (*SetObjectArrayElement)(JNIEnv *, jobjectArray, jsize, jobject);


    /**
     * ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);
     * 創(chuàng)建基本類型數(shù)組對(duì)象
     *
     * @param env JNI接口指針
     * @param length 數(shù)組大小
     *
     * @return 數(shù)組對(duì)象 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);
     * 返回基本類型數(shù)組中的數(shù)據(jù)桶雀,通過(guò)返回的指針可以訪問(wèn)這些數(shù)據(jù),若虛擬機(jī)支持pinning唬复,則指針指向原始數(shù)組魂拦,否則指向原始數(shù)組的拷貝
     * 返回的指針在Release<PrimitiveType>ArrayElements()調(diào)用前一直有效
     * 數(shù)組用使用結(jié)束后座咆,調(diào)用Release<PrimitiveType>ArrayElements,并在調(diào)用參數(shù)中決定是否把修改提交給java
     *
     * @param env JNI接口指針
     * @param array java數(shù)組
     * @param isCopy 指向boolean的指針,若不為NULL苍姜,則執(zhí)行了復(fù)制設(shè)為JNI_TRUE,否則設(shè)為JNI_FALSE
     *
     * @return 指向數(shù)組元素的指針 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不再需要訪問(wèn)這些數(shù)組,根據(jù)mode參數(shù)的不同,將決定是否把數(shù)組的修改復(fù)制到源數(shù)組
     *
     * @param env JNI接口指針
     * @param array java數(shù)組對(duì)象
     * @param elems 指向數(shù)組元素的指針
     * @param mode 釋放模式评疗,0:把數(shù)據(jù)復(fù)制回源數(shù)組并釋放elems緩沖區(qū),JNI_COMMIT:把數(shù)據(jù)復(fù)制回源數(shù)組但不釋放elems緩沖區(qū)茵烈,JNI_ABORT:不把數(shù)據(jù)復(fù)制回源數(shù)組百匆,釋放elems緩沖區(qū)
     */
    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);
     * 把基本類型數(shù)組拷貝到buf中
     *
     * @param env JNI接口指針
     * @param array java數(shù)組
     * @param start 開(kāi)始index
     * @param len 拷貝長(zhǎng)度
     * @param buf 目標(biāo)地址
     *
     * @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中的內(nèi)容拷貝回?cái)?shù)組中
     *
     * @param env JNI接口指針
     * @param array java數(shù)組
     * @param start 開(kāi)始index
     * @param len 拷貝長(zhǎng)度
     * @param buf 源數(shù)據(jù)
     *
     * @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類注冊(cè)本地方法
     *
     * @param env JNI接口指針
     * @param clazz class對(duì)象
     * @param methods clazz類中的本地方法,指向方法數(shù)組
     * @param nMethods 本地方法個(gè)數(shù)
     *
     * @return 0:成功呜投, 負(fù)數(shù):失敗
     *
     * @throws NoSuchMethodError
     */
    jint (*RegisterNatives)(JNIEnv *, jclass, const JNINativeMethod *, jint);


    /**
     * 取消clazz類本地方法的注冊(cè)
     *
     * @param env JNI接口指針
     * @param clazz class對(duì)象
     *
     * @return 0:成功加匈, 負(fù)數(shù):失敗
     */
    jint (*UnregisterNatives)(JNIEnv *, jclass);


    /**
     * 進(jìn)入與obj所引用的Java對(duì)象相關(guān)聯(lián)的監(jiān)控,obj 必須為非空
     *
     * @param env JNI接口指針
     * @param obj java對(duì)象 或 class對(duì)象
     *
     * @return 0:成功仑荐, 負(fù)數(shù):失敗
     */
    jint (*MonitorEnter)(JNIEnv *, jobject);


    /**
     * 退出與obj所引用的Java對(duì)象相關(guān)聯(lián)的監(jiān)控雕拼,obj 必須為非空
     * 當(dāng)前線程必須是與obj所引用的Java對(duì)象相關(guān)聯(lián)的監(jiān)控程序的所有者
     * 監(jiān)控程序次數(shù)的計(jì)數(shù)器減 1。如果計(jì)數(shù)器的值變?yōu)?0粘招,則釋放當(dāng)前線程的監(jiān)控程序
     *
     * @param env JNI接口指針
     * @param obj java對(duì)象 或 class對(duì)象
     *
     * @return 0:成功啥寇, 負(fù)數(shù):失敗
     */
    jint (*MonitorExit)(JNIEnv *, jobject);


    /**
     * 獲取當(dāng)前線程關(guān)聯(lián)的Java VM接口
     *
     * @param env JNI接口指針
     * @param vm java VM接口指針
     *
     * @return 0:成功, 負(fù)數(shù):失敗
     */
    jint (*GetJavaVM)(JNIEnv *, JavaVM **);


    /**
     * 從start index開(kāi)始洒扎,拷貝len個(gè)Unicode字符到buf
     *
     * @param env JNI接口指針
     * @param str string對(duì)象
     * @param start 開(kāi)始index
     * @param len 拷貝長(zhǎng)度
     * @param buf 目標(biāo)地址
     *
     * @throws StringIndexOutOfBoundsException
     */
    void (*GetStringRegion)(JNIEnv *, jstring, jsize, jsize, jchar *);


    /**
     * 從start index開(kāi)始辑甜,取出len個(gè)Unicode字符轉(zhuǎn)換為UTF-8編碼后拷貝到buf
     *
     * @param env JNI接口指針
     * @param str string對(duì)象
     * @param start 開(kāi)始index
     * @param len 拷貝長(zhǎng)度
     * @param buf 目標(biāo)地址
     *
     * @throws StringIndexOutOfBoundsException
     */
    void (*GetStringUTFRegion)(JNIEnv *, jstring, jsize, jsize, char *);


    /**
     * 與Get/Release<primitivetype>ArrayElements方法非常相似,在這個(gè)方法中VM盡量返回指向原始數(shù)組的指針
     *
     * @since JDK/JRE 1.2
     *
     * @param env JNI接口指針
     * @param array java數(shù)組
     * @param isCopy 指向boolean的指針逊笆,若不為NULL栈戳,則執(zhí)行了復(fù)制設(shè)為JNI_TRUE,否則設(shè)為JNI_FALSE
     *
     * @return 指向數(shù)組元素的指針 or NULL
     */
    void *(*GetPrimitiveArrayCritical)(JNIEnv *, jarray, jboolean *);
    void (*ReleasePrimitiveArrayCritical)(JNIEnv *, jarray, void *, jint);


    /**
     * 與Get/ReleaseStringChars方法非常相似难裆,在這個(gè)方法中VM盡量返回指向原始字符串的指針
     *
     * @since JDK/JRE 1.2
     *
     * @param env JNI接口指針
     * @param string String對(duì)象
     * @param isCopy 指向boolean的指針
     *
     * @return 指向字符串的指針 or NULL
     */
    const jchar *(*GetStringCritical)(JNIEnv *, jstring, jboolean *);
    void (*ReleaseStringCritical)(JNIEnv *, jstring, const jchar *);


    /**
     * 為傳入的obj創(chuàng)建弱全局引用
     * 弱全局引用不會(huì)阻止VM釋放所引用的對(duì)象子檀,程序中可以通過(guò)使用IsSameObject比較弱全局引用和NULL來(lái)確認(rèn)所引用的對(duì)象是否被釋放
     *
     * @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 *);


    /**
     * 創(chuàng)建并返回java.nio.ByteBuffer對(duì)象乃戈,該對(duì)象引用以address為開(kāi)始地址褂痰,大小為capacity的內(nèi)存塊
     *
     * @since JDK/JRE 1.4
     *
     * @param env JNI接口指針
     * @param address 開(kāi)始地址
     * @param capacity 內(nèi)存大小
     *
     * @return Jjava.nio.ByteBuffer or NULL
     *
     * @throws OutOfMemoryError
     */
    jobject (*NewDirectByteBuffer)(JNIEnv *, void *, jlong);


    /**
     * 根據(jù)java.nio.ByteBuffer對(duì)象,獲取相應(yīng)的內(nèi)存數(shù)據(jù)并返回開(kāi)始地址
     *
     * @since JDK/JRE 1.4
     *
     * @param env JNI接口指針
     * @param buf java.nio.ByteBuffer對(duì)象
     *
     * @return 數(shù)據(jù)的開(kāi)始地址 or NULL
     */
    void *(*GetDirectBufferAddress)(JNIEnv *, jobject);


    /**
     * 根據(jù)java.nio.ByteBuffer對(duì)象症虑,獲取相應(yīng)的內(nèi)存數(shù)據(jù)的大小
     *
     * @since JDK/JRE 1.4
     *
     * @param env JNI接口指針
     * @param buf java.nio.ByteBuffer對(duì)象
     *
     * @return 數(shù)據(jù)大小 or -1
     */
    jlong (*GetDirectBufferCapacity)(JNIEnv *, jobject);


    /**
     * 獲取java對(duì)象的引用類型缩歪,可能的返回值有:
     * JNIInvalidRefType
     * JNILocalRefType:局部引用
     * JNIGlobalRefType:全局引用
     * JNIWeakGlobalRefType :全局弱若引用
     *
     * @since JDK/JRE 1.6
     *
     * @param env JNI接口指針
     * @param obj java對(duì)象的引用
     *
     * @return 引用類型
     */
    jobjectRefType (*GetObjectRefType)(JNIEnv *, jobject);
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谍憔,隨后出現(xiàn)的幾起案子匪蝙,更是在濱河造成了極大的恐慌,老刑警劉巖习贫,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逛球,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡苫昌,警方通過(guò)查閱死者的電腦和手機(jī)颤绕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人奥务,你說(shuō)我怎么就攤上這事物独。” “怎么了氯葬?”我有些...
    開(kāi)封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵挡篓,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我溢谤,道長(zhǎng)瞻凤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任世杀,我火速辦了婚禮阀参,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瞻坝。我一直安慰自己蛛壳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布所刀。 她就那樣靜靜地躺著衙荐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪浮创。 梳的紋絲不亂的頭發(fā)上忧吟,一...
    開(kāi)封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音斩披,去河邊找鬼溜族。 笑死,一個(gè)胖子當(dāng)著我的面吹牛垦沉,可吹牛的內(nèi)容都是我干的煌抒。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼厕倍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼寡壮!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起讹弯,我...
    開(kāi)封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤况既,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后组民,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棒仍,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年邪乍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了降狠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡庇楞,死狀恐怖榜配,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吕晌,我是刑警寧澤蛋褥,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站睛驳,受9級(jí)特大地震影響烙心,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜乏沸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一淫茵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蹬跃,春花似錦匙瘪、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至翁都,卻和暖如春碍论,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背柄慰。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工鳍悠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人先煎。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓贼涩,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親薯蝎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子遥倦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容