本系列文章如下:
思維導(dǎo)圖如下:

本文主要是結(jié)合JNI的常用接口文檔進(jìn)行的翻譯主要是幫助我們更好的理解JNI中常用的API。具體如下:
一、Interface Function Table(接口函數(shù)表)
每個(gè)函數(shù)都可以通過JNIEnv參數(shù)訪問,JNIEnv類型是指向一個(gè)存放所有JNI接口指針的指針,其定義如下:
typedef const struct JNINativeInterface *JNIEnv;
虛擬機(jī)初始化函數(shù)表,如下面代碼所示,前三個(gè)條目是為了將來和COM兼容而保留的。另外,我們在函數(shù)表的開頭附近保留了一些額外的NULL條目,例如,可以在FindClass之后添加未來與類相關(guān)的JNI操作,而不是在表的末尾。請(qǐng)注意,函數(shù)表可以在所有JNI接口指針之間共享。
首先我們來看下JNINativeInterface
const struct JNINativeInterface ... = {
NULL,
NULL,
NULL,
NULL,
GetVersion,
DefineClass,
FindClass,
FromReflectedMethod,
FromReflectedField,
ToReflectedMethod,
GetSuperclass,
IsAssignableFrom,
ToReflectedField,
Throw,
ThrowNew,
ExceptionOccurred,
ExceptionDescribe,
ExceptionClear,
FatalError,
PushLocalFrame,
PopLocalFrame,
NewGlobalRef,
DeleteGlobalRef,
DeleteLocalRef,
IsSameObject,
NewLocalRef,
EnsureLocalCapacity,
AllocObject,
NewObject,
NewObjectV,
NewObjectA,
GetObjectClass,
IsInstanceOf,
GetMethodID,
CallObjectMethod,
CallObjectMethodV,
CallObjectMethodA,
CallBooleanMethod,
CallBooleanMethodV,
CallBooleanMethodA,
CallByteMethod,
CallByteMethodV,
CallByteMethodA,
CallCharMethod,
CallCharMethodV,
CallCharMethodA,
CallShortMethod,
CallShortMethodV,
CallShortMethodA,
CallIntMethod,
CallIntMethodV,
CallIntMethodA,
CallLongMethod,
CallLongMethodV,
CallLongMethodA,
CallFloatMethod,
CallFloatMethodV,
CallFloatMethodA,
CallDoubleMethod,
CallDoubleMethodV,
CallDoubleMethodA,
CallVoidMethod,
CallVoidMethodV,
CallVoidMethodA,
CallNonvirtualObjectMethod,
CallNonvirtualObjectMethodV,
CallNonvirtualObjectMethodA,
CallNonvirtualBooleanMethod,
CallNonvirtualBooleanMethodV,
CallNonvirtualBooleanMethodA,
CallNonvirtualByteMethod,
CallNonvirtualByteMethodV,
CallNonvirtualByteMethodA,
CallNonvirtualCharMethod,
CallNonvirtualCharMethodV,
CallNonvirtualCharMethodA,
CallNonvirtualShortMethod,
CallNonvirtualShortMethodV,
CallNonvirtualShortMethodA,
CallNonvirtualIntMethod,
CallNonvirtualIntMethodV,
CallNonvirtualIntMethodA,
CallNonvirtualLongMethod,
CallNonvirtualLongMethodV,
CallNonvirtualLongMethodA,
CallNonvirtualFloatMethod,
CallNonvirtualFloatMethodV,
CallNonvirtualFloatMethodA,
CallNonvirtualDoubleMethod,
CallNonvirtualDoubleMethodV,
CallNonvirtualDoubleMethodA,
CallNonvirtualVoidMethod,
CallNonvirtualVoidMethodV,
CallNonvirtualVoidMethodA,
GetFieldID,
GetObjectField,
GetBooleanField,
GetByteField,
GetCharField,
GetShortField,
GetIntField,
GetLongField,
GetFloatField,
GetDoubleField,
SetObjectField,
SetBooleanField,
SetByteField,
SetCharField,
SetShortField,
SetIntField,
SetLongField,
SetFloatField,
SetDoubleField,
GetStaticMethodID,
CallStaticObjectMethod,
CallStaticObjectMethodV,
CallStaticObjectMethodA,
CallStaticBooleanMethod,
CallStaticBooleanMethodV,
CallStaticBooleanMethodA,
CallStaticByteMethod,
CallStaticByteMethodV,
CallStaticByteMethodA,
CallStaticCharMethod,
CallStaticCharMethodV,
CallStaticCharMethodA,
CallStaticShortMethod,
CallStaticShortMethodV,
CallStaticShortMethodA,
CallStaticIntMethod,
CallStaticIntMethodV,
CallStaticIntMethodA,
CallStaticLongMethod,
CallStaticLongMethodV,
CallStaticLongMethodA,
CallStaticFloatMethod,
CallStaticFloatMethodV,
CallStaticFloatMethodA,
CallStaticDoubleMethod,
CallStaticDoubleMethodV,
CallStaticDoubleMethodA,
CallStaticVoidMethod,
CallStaticVoidMethodV,
CallStaticVoidMethodA,
GetStaticFieldID,
GetStaticObjectField,
GetStaticBooleanField,
GetStaticByteField,
GetStaticCharField,
GetStaticShortField,
GetStaticIntField,
GetStaticLongField,
GetStaticFloatField,
GetStaticDoubleField,
SetStaticObjectField,
SetStaticBooleanField,
SetStaticByteField,
SetStaticCharField,
SetStaticShortField,
SetStaticIntField,
SetStaticLongField,
SetStaticFloatField,
SetStaticDoubleField,
NewString,
GetStringLength,
GetStringChars,
ReleaseStringChars,
NewStringUTF,
GetStringUTFLength,
GetStringUTFChars,
ReleaseStringUTFChars,
GetArrayLength,
NewObjectArray,
GetObjectArrayElement,
SetObjectArrayElement,
NewBooleanArray,
NewByteArray,
NewCharArray,
NewShortArray,
NewIntArray,
NewLongArray,
NewFloatArray,
NewDoubleArray,
GetBooleanArrayElements,
GetByteArrayElements,
GetCharArrayElements,
GetShortArrayElements,
GetIntArrayElements,
GetLongArrayElements,
GetFloatArrayElements,
GetDoubleArrayElements,
ReleaseBooleanArrayElements,
ReleaseByteArrayElements,
ReleaseCharArrayElements,
ReleaseShortArrayElements,
ReleaseIntArrayElements,
ReleaseLongArrayElements,
ReleaseFloatArrayElements,
ReleaseDoubleArrayElements,
GetBooleanArrayRegion,
GetByteArrayRegion,
GetCharArrayRegion,
GetShortArrayRegion,
GetIntArrayRegion,
GetLongArrayRegion,
GetFloatArrayRegion,
GetDoubleArrayRegion,
SetBooleanArrayRegion,
SetByteArrayRegion,
SetCharArrayRegion,
SetShortArrayRegion,
SetIntArrayRegion,
SetLongArrayRegion,
SetFloatArrayRegion,
SetDoubleArrayRegion,
RegisterNatives,
UnregisterNatives,
MonitorEnter,
MonitorExit,
GetJavaVM,
GetStringRegion,
GetStringUTFRegion,
GetPrimitiveArrayCritical,
ReleasePrimitiveArrayCritical,
GetStringCritical,
ReleaseStringCritical,
NewWeakGlobalRef,
DeleteWeakGlobalRef,
ExceptionCheck,
NewDirectByteBuffer,
GetDirectBufferAddress,
GetDirectBufferCapacity,
GetObjectRefType
};
下面我們就詳細(xì)介紹下
二、獲取JNI版本信息
在JNIEnv指針中,有個(gè)函數(shù)用于獲取JNI的版本:
jint GetVersion(JNIEnv *env);
該方法主要返回本地JNI方法接口的版本信息。在不同的JDK環(huán)境下返回值是不同的,具體如下:
- 在JDK/JRE 1.1中,返回
0x00010001- 在JDK/JRE 1.2中,返回
0x00010002- 在JDK/JRE 1.3中,返回
0x00010004- 在JDK/JRE 1.4中,返回
0x00010006
上面這些數(shù)字可不是我亂拍的,其實(shí)是早就被定義為一個(gè)宏了,如下:
#define JNI_VERSION_1_1 0x00010001
#define JNI_VERSION_1_2 0x00010002
/* Error codes */
#define JNI_EDETACHED (-2) /* thread detached from the VM */
#define JNI_EVERSION (-3) /* JNI version error
SINCE JDK/JRE 1.4:
#define JNI_VERSION_1_4 0x00010004
SINCE JDK/JRE 1.6:
#define JNI_VERSION_1_6 0x00010006
三、Java 類 操作
(一)、定義類(加載類)
jclass DefineClass(JNIEnv *env,const char* name,jobject loader,const jbyte *buf, jsize bufLen)
這個(gè)函數(shù),主要是從包含數(shù)據(jù)的buffer中加載類,該buffer包含類調(diào)用時(shí)未被虛擬機(jī)所引用的原始類數(shù)據(jù)。
入?yún)⒔忉專?/p>
- env:JNI接口指針
- name:所定義的類名或者接口名,該字符串有modefied UTF-8編碼
- loader:指派給定義的類加載器
- buf:包含.class文件數(shù)據(jù)的buffer
- bufLen:buffer長度
返回:Java類對(duì)象,當(dāng)錯(cuò)誤出現(xiàn)時(shí)返回NULL
可能拋出的異常:
- 如果沒有指定這個(gè)Java類的,則會(huì)拋出
ClassFormatError- 如果是一個(gè)類/接口是它自己的一個(gè)父類/父接口,則會(huì)拋出
ClassCircularityError- 如果內(nèi)存不足,則會(huì)拋出
OutOfMemoryError- 如果想嘗試在Java包中定義一個(gè)類,則會(huì)拋出
SecurityException
(二)、查找類
jclass FindClass(JNIEnv *env,const char *name);
這里面有兩種情況一個(gè)是JDK release1.1,另外一種是JDK release 1.2
。從JDK release 1.1,該函數(shù)加載一個(gè)本地定義類,它搜索CLASSPATH環(huán)境變量里的目錄及zip文件查找特定名字的類。自從Java 2 release 1.2,Java安全模型允許非系統(tǒng)類加載跟調(diào)用本地方法。FindClass定義與當(dāng)前本地方法關(guān)聯(lián)的類加載,也就是聲明本地方法的類的類加載類。如果本地方法屬于系統(tǒng)類,則不會(huì)涉及類加載器;否則,將調(diào)用適當(dāng)?shù)念惣虞d來加載和鏈接指定的類。從Java 2 SDK1.2版本開始,通過調(diào)用接口調(diào)用FindClass時(shí),沒有當(dāng)前的本機(jī)方法或關(guān)聯(lián)的的類加載器。在這種情況下,在這種情況下,使用ClassLoader.getSystemClassLoader的結(jié)果。這是虛擬機(jī)為應(yīng)用程序創(chuàng)建的類加載器,并且能夠找到j(luò)ava.class.path屬性列出的類。
入?yún)⒔忉專?/p>
- env:JNI接口指針
- name:一個(gè)完全限定的類名,即包含“包名”+“/”+類名。舉個(gè)例子:如
java.lang.String,該參數(shù)為java/lang/String;如果類名以[開頭,將返回一個(gè)數(shù)組類。比如數(shù)組類的簽名為java.lang.Object[],該參數(shù)應(yīng)該為"[Ljava/lang/Object"
返回:
返回對(duì)應(yīng)完全限定類對(duì)象,當(dāng)找不到類時(shí),返回NULL
可能拋出的異常:
- 如果沒有指定這個(gè)Java類的,則會(huì)拋出
ClassFormatError- 如果是一個(gè)類/接口是它自己的一個(gè)父類/父接口,則會(huì)拋出
ClassCircularityError- 如果沒有找到該類/接口的定義,則拋出
NoClassDefFoundError- 如果內(nèi)存不足,則會(huì)拋出
OutOfMemoryError
(三)、查找父類
jclass GetSuperclass(JNIEnv *env,jclass clazz);
如果clazz不是Object類,則此函數(shù)將返回表示該clazz的父類的Class對(duì)象,如果該類是Object,或者clazz代表接口,則此函數(shù)返回NULL。
入?yún)⒔忉專?/p>
- env:JNI接口指針
- clazz:Java的Class類
返回:
如果clazz有父類則返回其父類,如果沒有其父類則返回NULL
(四)、安全轉(zhuǎn)換
jboolean IsAssignableFrom(JNIEnv *env,jclass clazz1,jclass clazz2);
判斷clazz1的對(duì)象是否可以安全地轉(zhuǎn)化為clazz2的對(duì)象
入?yún)⒔忉專?/p>
- env:JNI接口指針
- clazz1:Java的Class類,即需要被轉(zhuǎn)化的類
- clazz2:Java的Class類,即需要轉(zhuǎn)化為目標(biāo)的類
返回:
如果滿足以下任一條件,則返回JNI_TRUE:
- 如果clazz1和clazz2是同一個(gè)Java類。
- 如果clazz1是clazz2的子類
- 如果clazz1是clazz2接口的實(shí)現(xiàn)類
四、異常 操作
(一)、拋出異常
jint Throw(JNIEnv *env,jthrowable obj);
傳入一個(gè)jthrowable對(duì)象,并且在JNI并將其拋起
入?yún)⒔忉專?/p>
- env:JNI接口指針
- jthrowable:一個(gè)Java的java.lang.Throwable對(duì)象
返回:
成功返回0,失敗返回一個(gè)負(fù)數(shù)。
可能拋出的異常:
拋出一個(gè)java.lang.Throwable 對(duì)象
(二)、構(gòu)造一個(gè)新的異常并拋出
jint ThrowNew(JNIEnv *env,jclass clazz,const char* message);
傳入一個(gè)message,并用其構(gòu)造一個(gè)異常并且拋出。
入?yún)⒔忉專?/p>
- env:JNI接口指針
- jthrowable:一個(gè)Java的java.lang.Throwable對(duì)象
- message:用于構(gòu)造一個(gè)java.lang.Throwable對(duì)象的消息,該字符串用modified UTF-8編碼
返回:
如果成功返回0,失敗返回一個(gè)負(fù)數(shù)
可能拋出的異常:
拋出一個(gè)新構(gòu)造的java.lang.Throwable 對(duì)象
(三)、檢查是否發(fā)生異常,并拋出異常
jthrowable ExceptionOccurred(JNIEnv *env);
檢測是否發(fā)生了異常,如果發(fā)生了,則返回該異常的引用(再調(diào)用ExceptionClear()函數(shù)前,或者Java處理異常前),如果沒有發(fā)生異常,則返回NULL。
入?yún)⒔忉專?/p>
- env:JNI接口指針
返回:
jthrowable的異常引用或者NULL
(四)、打印異常的堆棧信息
void ExceptionDescribe(JNIEnv *env)
打印這個(gè)異常的堆棧信息
入?yún)⒔忉專?/p>
- env:JNI接口指針
(五)、清除異常的堆棧信息
void ExceptionClear(JNIEnv *env);
清除正在拋出的異常,如果當(dāng)前沒有異常被拋出,這個(gè)函數(shù)不起作用
入?yún)⒔忉專?/p>
- env:JNI接口指針
(六)、致命異常
void FatalError(JNIEnv *env,const char* msg);
致命異常,用于輸出一個(gè)異常信息,并終止當(dāng)前VM實(shí)例,即退出程序。
入?yún)⒔忉專?/p>
- env:JNI接口指針
- msg:異常的錯(cuò)誤信息,該字符串用modified UTF-8編碼
(七)、僅僅檢查是否發(fā)生異常
jboolean ExceptionCheck(JNIEnv *env);
檢查是否已經(jīng)發(fā)生了異常,如果已經(jīng)發(fā)生了異常,則返回JNI_TRUE,否則返回JNI_FALSE
入?yún)⒔忉專?/p>
- env:JNI接口指針
返回:
如果已經(jīng)發(fā)生異常,返回JNI_TRUE,如果沒有發(fā)生異常則返回JNI_FALSE
五、全局引用和局部引用
(一)、創(chuàng)建全局引用
jobject NewGlobalRef(JNIEnv *env,object obj);
給對(duì)象obj創(chuàng)建一個(gè)全局引用,obj可以是全局或局部引用。全局引用必須通過DeleteGlobalRef()顯示處理。
參數(shù)解釋:
- env:JNI接口指針
- obj:object對(duì)象
返回:
全局引用jobject,如果內(nèi)存溢出則返回NULL
(二)、刪除全局引用
void DeleteGlobalRef(JNIEnv *env,jobject globalRef);
刪除全局引用
參數(shù)解釋:
- env:JNI接口指針
- globalRef:需要被刪除的全局引用
(三)、刪除局部引用
局部引用只在本地接口調(diào)用時(shí)的生命周期內(nèi)有效,當(dāng)本地方法返回時(shí),它們會(huì)被自動(dòng)釋放。每個(gè)局部引用都會(huì)消耗一定的虛擬機(jī)資源,雖然局部引用可以被自動(dòng)銷毀,但是程序員也需要注意不要在本地方法中過度分配局部引用,過度分配局部引用會(huì)導(dǎo)致虛擬機(jī)在執(zhí)行本地方法時(shí)內(nèi)存溢出。
void DeleteLocalRef(JNIEnv *env, jobject localRef);
通過localRef刪除局部引用
參數(shù)解釋
- env:JNI接口指針
- localRef:需要被刪除的局部引用
JDK/JRE 1.1提供了上面的DeleteLocalRef函數(shù),這樣程序員就可以手動(dòng)刪除本地引用。
從JDK/JRE 1.2開始,提供可一組生命周期管理的函數(shù),他們是下面四個(gè)函數(shù)。
(四)、設(shè)定局部變量的容量
jint EnsureLocalCapacity(JNIEnv *env,jint capacity);
在當(dāng)前線程中,通過傳入一個(gè)容量capacity,,限制局部引用創(chuàng)建的數(shù)量。成功則返回0,否則返回一個(gè)負(fù)數(shù),并拋出一個(gè)OutOfMemoryError。VM會(huì)自動(dòng)確保至少可以創(chuàng)建16個(gè)局部引用。
參數(shù)解釋
- env:JNI接口指針
- capacity:容量
返回:
成功返回0,失敗返回一個(gè)負(fù)數(shù),并會(huì)拋出一個(gè)OutOfMemoryError
為了向后兼容,如果虛擬機(jī)創(chuàng)建了超出容量的局部引用。VM調(diào)用FatalError,來保證不能創(chuàng)建更多的本地引用。(如果是debug模式,虛擬機(jī)回想用戶發(fā)出warning,并提示創(chuàng)建了更多的局部引用,在JDK中,程序員可以提供-verbose:jni命令行選項(xiàng)來打開這個(gè)消息)
(五)、在老的上創(chuàng)建一個(gè)新的幀
jint PushLocalFram(JNIEnv *env ,jint capacity);
在已經(jīng)設(shè)置設(shè)置了局部變量容量的情況下, 重新創(chuàng)建一個(gè)局部變量容器。成功返回0,失敗返回一個(gè)負(fù)數(shù)并拋出一個(gè)OutOfMemoryError異常。
注意:當(dāng)前的局部幀中,前面的局部幀創(chuàng)建的局部引用仍然是有效的
參數(shù)解釋
- env:JNI接口指針
- capacity:容量
(六)、釋放一個(gè)局部引用
jobject PopLocalFrame(JNIEnv *env,jobject result)
彈出當(dāng)前的局部引用幀,并且釋放所有的局部引用。返回在之前局部引用幀與給定result對(duì)象對(duì)應(yīng)的局部引用。如果不需要返回任何引用,則設(shè)置result為NULL
參數(shù)解釋
- env:JNI接口指針
- result:需要釋放的局部引用
(七)、創(chuàng)建一個(gè)局部引用
jobject NewLocalRef(JNIEnv *env,jobject ref);
創(chuàng)建一個(gè)引用自ref的局部引用。ref可以是全局或者局部引用,如果ref為NULL,則返回NULL。
參數(shù)解釋
- env:JNI接口指針
- ref:可以試試局部引用也可以是全局引用。
(八)、弱全局引用
弱全局引用是一種特殊的全局引用,不像一般的全局引用,一個(gè)弱全局引用允許底層Java對(duì)象能夠被垃圾回收。弱全局引用能夠應(yīng)用在任何全局或局部引用被使用的地方。當(dāng)垃圾回收器運(yùn)行的時(shí)候,如果對(duì)象只被弱引用所引用時(shí),它將釋放底層變量。一個(gè)弱阮菊引用指向一個(gè)被釋放的對(duì)象相當(dāng)于等于NULL。編程人員可以通過使用isSampleObject對(duì)比弱引用和NULL來檢測一個(gè)弱全局應(yīng)用是否指向一個(gè)被釋放的對(duì)象。弱全局引用在JNI中是Java弱引用的一個(gè)簡化版本,在Java平臺(tái)API中有有效。
當(dāng)Native方法正在運(yùn)行的時(shí)候,垃圾回收器可能正在工作,被弱引用所指向的對(duì)象可能在任何時(shí)候被釋放。弱全局引用能夠應(yīng)用在任何全局引用所使用的地方,通常是不太適合那么做的,因?yàn)樗鼈兛赡茉诓蛔⒁獾臅r(shí)候編程N(yùn)ULL。
當(dāng)IsSampleObject能夠識(shí)別一個(gè)弱全局引用是不是指向一個(gè)被釋放的對(duì)象,但是這不妨礙這個(gè)對(duì)象在被檢測之后馬上被釋放。這就說明了,程序員不能依賴這個(gè)方法來識(shí)別一個(gè)弱全局引用是否能夠在后續(xù)的JNI函數(shù)調(diào)用中被使用。
如果想解決上述的問題,建議使用JNI函數(shù)NewLocalRef或者NewGlobalRef來用標(biāo)準(zhǔn)的全局也引用或者局部引用來指向相同的對(duì)象。如果這個(gè)獨(dú)享已經(jīng)被釋放了這些函數(shù)會(huì)返回NULL。否則會(huì)返回一個(gè)強(qiáng)引用(這樣就可以保證這個(gè)對(duì)象不會(huì)被釋放)。當(dāng)不需要訪問這個(gè)對(duì)象時(shí),新的引用必須顯式被刪除。
1、創(chuàng)建全局弱引用
jweak NewWeakGlobalRef(JNIEnv *env,jobject obj);
創(chuàng)建一個(gè)新的弱全局引用。如果obj指向NULL,則返回NULL。如果VM內(nèi)存溢出,將會(huì)拋出異常OutOfMemoryError。
參數(shù)解釋
- env:JNI接口指針
- obj:引用對(duì)象
返回:
全局弱引用
2、刪除全局弱引用
void DeleteWeakGlobalRef(JNIEnv *env,jweak obj);
VM根據(jù)所給定的弱全局引用刪除對(duì)應(yīng)的資源。
參數(shù)解釋
- env:JNI接口指針
- obj:將刪除的弱全局引用
六、對(duì)象操作
(一)、直接創(chuàng)建一個(gè)Java對(duì)象
jobject AllocObject(JNIEnv *env,jclass clazz);
不借助任何構(gòu)造函數(shù)的情況下分配一個(gè)新的Java對(duì)象,返回對(duì)象的一個(gè)引用。
參數(shù)解釋:
- env:JNI接口指針
- clazz::Java類對(duì)象
返回:
返回一個(gè)Java對(duì)象,如果該對(duì)象無法被創(chuàng)建,則返回NULL。
異常:
- 如果該類是接口或者是抽象類,則拋出InstantiationException
- 如果是內(nèi)存溢出,則拋出OutOfMemoryError
(二)、根據(jù)某個(gè)構(gòu)造函數(shù)來創(chuàng)建Java對(duì)象
jobject NewObject(JNIEnv *env,jclass clazz,jmethodID methodID,...);
jobject NewObjectA(JNIEnv *env,jclass clazz,jmethodID methodID,const jvalue *args);
jobject NewObjectV(JNIEnv *env,jclass clazz,jmethodID methodID,va_list args);
構(gòu)造一個(gè)新的Java對(duì)象,methodID表明需要調(diào)用一個(gè)構(gòu)造函數(shù)。這個(gè)ID必須通過調(diào)用GetMethodID()獲得,GetMethodID()為函數(shù)名,void(V)為返回值。clazz參數(shù)不能紙箱一個(gè)數(shù)組類
-
NewObject:需要把所有構(gòu)造函數(shù)的入?yún)?,放在參?shù)methodID之后。NewObject()接受這些參數(shù)并將它們傳遞給需要被調(diào)用的Java的構(gòu)造函數(shù) -
NewObjectA:在methodID后面,放了一個(gè)類型為jvalue的參數(shù)數(shù)組——args,該數(shù)組存放著所有需要傳遞給構(gòu)造函數(shù)的參數(shù)。NewObjectA()接收到這個(gè)數(shù)組中的所有參數(shù),并且按照順序?qū)⑺鼈儌鬟f給需要調(diào)用的Java方法。 -
NewObjectV:在methodID后面,放了一個(gè)類型為va_list的args,參數(shù)存放著所有需要傳遞給構(gòu)造函數(shù)的參數(shù)。NewObjectv()接收到所有的參數(shù),并且按照順序?qū)⑺鼈儌鬟f給需要調(diào)用的Java方法。
參數(shù)解釋:
- env:JNI接口指針
- clazz::Java類
- methodID:構(gòu)造函數(shù)的方法ID
附加參數(shù):
- NewObject的附加參數(shù):arguments是構(gòu)造函數(shù)的參數(shù)
- NewObjectA的附加參數(shù):args是構(gòu)造函數(shù)的參數(shù)數(shù)組
- NewObjectV的附加參數(shù):args是構(gòu)造函數(shù)的參數(shù)list
返回:
Java對(duì)象,如果無法創(chuàng)建該對(duì)象,則返回NULL
異常:
如果傳入的類是接口或者抽象類,則拋出InstantiationException
如果內(nèi)存溢出,則拋出OutOfMemoryError
所有的異常都是通過構(gòu)造函數(shù)拋出
(三)、獲取某個(gè)對(duì)象的“類”
jclass GetObjectClass(JNIEnv *env,object obj);
返回obj對(duì)應(yīng)的類
參數(shù)解釋
- env:JNI接口指針
- obj:Java對(duì)象,不能為NULL
參數(shù):
env:JNI接口指針
obj:JAVA對(duì)象,不能為NULL
返回:
返回一個(gè)Java“類”對(duì)象
(四)、獲取某個(gè)對(duì)象的“類型”
jobjectRefType GetObjectRefType(JNIEnv *env,jobject obj);
返回obj參數(shù)所以指向?qū)ο蟮念愋停瑓?shù)obj可以是局部變量,全局變量或者若全局引用。
參數(shù)解釋
- env:JNI接口指針
- obj:局部、全局或弱全局引用
返回:
- JNIInvalidRefType=0:代表obj參數(shù)不是有效的引用類型
- JNILocalRefType=1:代表obj參數(shù)是局部變量類型
- JNIGlobalRefType=2:代表obj參數(shù)是全局變量類型
- JNIWeakGlobalRefType=3:代表obj參數(shù)是弱全局有效引用
無效的引用就是沒有引用的引用。也就是說,obj的指針沒有指向內(nèi)存中創(chuàng)建函數(shù)時(shí)候的地址,或者已經(jīng)從JNI函數(shù)中返回了。所以說NULL就是無效的引用。并且GetObjectRefType(env,NULL)將返回類型是JNIInvalidRefType。但是空引用返回的不是JNIInvalidRefType,而是它被創(chuàng)建時(shí)候的引用類型。
PS:不能在引用在刪除的時(shí)候,調(diào)用該函數(shù)
(五)、判斷某個(gè)對(duì)象是否是某個(gè)“類”的子類
jboolean IsInstanceOf(JNIEnv *env, jobject obj,jclass clazz);
測試obj是否是clazz的一個(gè)實(shí)例
參數(shù):
- env:JNI接口指針
- obj:一個(gè)Java對(duì)象
- clazz:一個(gè)Java的類
返回:
如果obj是clazz的實(shí)例,則返回JNI_TRUE;否則則返回JNI_FALSE;一個(gè)空對(duì)象可以是任何類的實(shí)例。
(六)、判斷兩個(gè)引用是否指向同一個(gè)引用
jboolean IsSampleObject(JNIEnv *env,jobject ref1,jobject ref2);
判斷兩個(gè)引用是否指向同一個(gè)對(duì)象
參數(shù)解釋:
- env:JNI接口指針
- ref1:Java對(duì)象
- ref2:Java對(duì)象
返回:
如果同一個(gè)類對(duì)象,返回JNI_TRUE;否則,返回JNI_FALSE;
(七)、返回屬性id
jfieldID GetFieldID(JNIEnv *env,jclass clazz,const char *name,const char *sig);
獲取某個(gè)類的非靜態(tài)屬性id。通過方法屬性名以及·屬性的簽名(也就是屬性的類型),來確定對(duì)應(yīng)的是哪個(gè)屬性。通過檢索這個(gè)屬性ID,我們就可以調(diào)用Get <type>Field和Set <type>Field了,就是我們常用的get和set`方法
參數(shù)解釋:
- env:JNI接口指針
- clazz:一個(gè)Java類對(duì)象
- name:以"0"結(jié)尾的,而且字符類型是"utf-8"的屬性名稱
- sig:以"0"結(jié)尾的,而且字符類型是"utf-8"的屬性簽名
返回
屬性對(duì)應(yīng)ID,如果操作失敗,則返回NULL
異常:
如果找不到指定的屬性,則拋出NoSuchFieldError
如果類初始化失敗,則拋出ExceptionInitializerError
如果內(nèi)存不足了,則拋出OutOfMemoryError
PS:
GetFieldID()可能會(huì)導(dǎo)致還未初始化的類開始初始化,同時(shí)在獲取數(shù)組的長度不能使用GetFieldID(),而應(yīng)該使用GetArrayLength()。
(八)、返回屬性id系列
NativeType GetField(JNIEnv *env,jobject obj,jfieldID fielD);
返回某個(gè)類的非靜態(tài)屬性的值,這是一組函數(shù)的簡稱,具體如下:
jobject GetObjectField(JNIEnv *env,jobject obj,jfieldID fielD)
jboolean GetBooleanField(JNIEnv *env,jobject obj,jfieldID fielD)
jbyte GetByteField(JNIEnv *env,jobject obj,jfieldID fielD)
jchar GetCharField(JNIEnv *env,jobject obj,jfieldID fielD)
jshort GetShortField(JNIEnv *env,jobject obj,jfieldID fielD)
jint GetIntField(JNIEnv *env,jobject obj,jfieldID fielD)
jlong GetLongField(JNIEnv *env,jobject obj,jfieldID fielD)
jfloat GetFloatField(JNIEnv *env,jobject obj,jfieldID fielD)
jdouble GetDoubleField(JNIEnv *env,jobject obj,jfieldID fielD)
參數(shù)解釋:
env:JNI接口指針
obj:Java對(duì)象,不能為空
fieldID:有效的fieldID
返回:
對(duì)應(yīng)屬性的值
(九)、設(shè)置屬性id系列
void Set<type>Field(JNIEnv *env,jobject obj,jfieldID fieldID,NativeType value)
設(shè)置某個(gè)類的的非靜態(tài)屬性的值。其中具體哪個(gè)屬性通過GetFieldID()來確定哪個(gè)屬性。這是一組函數(shù)的簡稱,具體如下:
void SetObjectField(jobject)
void SetBooleanField(jboolean)
void SetByteField(jbyte)
void SetCharField(jchar)
void SetShortField(jshort)
void SetIntField(jint)
void SetLongField(jlong)
void SetFloatField(jfloat)
void SetDoubleField(jdouble)
參數(shù)解釋:
- env:JNI接口指針
- obj:Java對(duì)象,不能為空
- fieldID:有效的屬性ID
- value:屬性的新值
(十)、獲取某個(gè)類的某個(gè)方法id
jmethodID GetMethodID(JNIEnv *env,jclass clazz,const char*name,const char* sig);
返回某個(gè)類或者接口的方法ID,該方法可以是被定義在clazz的父類中,然后被clazz繼承。我們是根據(jù)方法的名字以及簽名來確定一個(gè)方法的。
PS:
GetMethodID()會(huì)造成還未初始化的類,進(jìn)行初始化
如果想獲取構(gòu)造函數(shù)的ID,請(qǐng)?zhí)峁?code>init作為方法名稱,并將void(V)作為返回類型
參數(shù)解釋:
- env:JNI接口指針
- clazz:Java類對(duì)象
- name:以0結(jié)尾的,并且是"utf-8"的字符串的方法名稱
- sig:以0結(jié)尾的,并且是"utf-8"的字符串的方法簽名
返回:
返回一個(gè)方法ID,沒有找到指定的方法,則返回NULL
異常:
如果找不到指定的方法,則拋出NoSuchMethodError
如果累初始化失敗,則拋出ExceptionInInitializerError
如果內(nèi)存不夠,則拋出OutOfMemoryError
(十一)、調(diào)用Java實(shí)例的某個(gè)非靜態(tài)方法“系列”
NativeType Call<type>Method(JNIEnv *env,jobject obj,jmethodID methodID,...);
NativeType Call<type>MethodA(JNIEnv *env,jobjct obj,jmethodID methodID ,const jvalue *args);
NativeType Call<type>MethodV(JNEnv *env,jobject obj,jmethodID methodID,va_list args);
這一些列都是在native中調(diào)用Java對(duì)象的某個(gè)非靜態(tài)方法,它們的不同點(diǎn)在于傳參不同。是根據(jù)方法ID來指定對(duì)應(yīng)的Java對(duì)象的某個(gè)方法。methodID參數(shù)需要調(diào)用GetMethodID()獲取。
PS:當(dāng)需要調(diào)用某個(gè)"private"函數(shù)或者構(gòu)造函數(shù)時(shí),這個(gè)methodID必須是obj類的方法,不能是它的父類的方法。
下面我們來看下他們的不同點(diǎn)
- CallMethod:需要把方法的
入?yún)?/code>放在參數(shù)methodID后面。CallMethod()其實(shí)把這些參數(shù)傳遞給需要調(diào)用的Java方法。 - CallMethodA:在
methodID后面,有一個(gè)類型為jvalue的args數(shù)組,該數(shù)組存放所有需要傳遞給構(gòu)造函數(shù)的參數(shù)。CallMethodA()收到這個(gè)數(shù)組中的參數(shù),是按照順序?qū)⑺麄儌鬟f給對(duì)應(yīng)的Java方法 - CallMethodV:在
methodID后面,有一個(gè)類型Wieva_list的參數(shù)args,它存放著所有需要傳遞給構(gòu)造函數(shù)的參數(shù)。CallMethodV()接收所有的參數(shù),并且按照順序?qū)⑺鼈儌鬟f給需要調(diào)用的Java方法。
Call<type>Method Routine Name Native Type
CallVoidMethod()
CallVoidMethodA() void
CallVoidMethodV()
CallObjectMethod()
CallObjectMethodA() jobject
CallObjectMethodV()
CallBooleanMethod()
CallBooleanMethodA() jboolean
CallBooleanMethodV()
CallByteMethod()
CallByteMethodA() jbyte
CallByteMethodV()
CallCharMethod()
CallCharMethodA() jchar
CallCharMethodV()
CallShortMethod()
CallShortMethodA() jshort
CallShortMethodV()
CallIntMethod()
CallIntMethodA() jint
CallIntMethodV()
CallLongMethod()
CallLongMethodA()
CallLongMethodV()
CallFloatMethod()
CallFloatMethodA() jlong
CallFloatMethodV()
CallDoubleMethod()
CallDoubleMethodA() jfloat
CallDoubleMethodV()
參數(shù)解釋:
- env:JNI接口指針
- obj:對(duì)應(yīng)的Java對(duì)象
- methodID:某個(gè)方法的方法id
返回:
返回調(diào)用Java方法對(duì)應(yīng)的結(jié)果
異常:
在Java方法執(zhí)行過程中產(chǎn)生的異常。
(十二)、調(diào)用某個(gè)類的非抽象方法
調(diào)用父類中的實(shí)例方法,如下系列
CallNonvirtual<type>Method
CallNonvirtual<type>MethodA
CallNonvirtual<type>MethodV
具體如下:
NativeType CallNonvirtual<Type>Method(JNIEnv *env,jobject obj,jclass clazz,jmethodID methodID,....);
NativeType CallNonvirtual<Type>MethodA(JNIEnv *env,jobject obj,jclass clazz,jmethodID methodID,const jvalue *args);
NativeType CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj,
jclass clazz, jmethodID methodID, va_list args);
這一系列操作就是根據(jù)特定的類,和其方法ID來調(diào)用Java對(duì)象的實(shí)例的非靜態(tài)方法,methodID參數(shù)需要調(diào)用GetMethodID()獲取。
CallNonvirtual<Type>Method和Call<type>Method是不同的,其中CallNonvirtual<Type>Method是基于"類",而和Call<type>Method是基于類的對(duì)象。所以說CallNonvirtual<Type>Method`的入?yún)⑹?clazz,methodID必須來源與obi的類,而不是它的父類
下面我們來看下他們的不同點(diǎn)
- CallNonvirtual<type>Method :需要把方法的
入?yún)?/code>放在參數(shù)methodID后面。CallNonvirtual<type>Method()其實(shí)把這些參數(shù)傳遞給需要調(diào)用的Java方法。 - CallNonvirtual<type>Method:在
methodID后面,有一個(gè)類型為jvalue的args數(shù)組,該數(shù)組存放所有需要傳遞給構(gòu)造函數(shù)的參數(shù)。CallNonvirtual<type>Method()收到這個(gè)數(shù)組中的參數(shù),是按照順序?qū)⑺麄儌鬟f給對(duì)應(yīng)的Java方法 - CallNonvirtual<type>MethodV :在
methodID后面,有一個(gè)類型Wieva_list的參數(shù)args,它存放著所有需要傳遞給構(gòu)造函數(shù)的參數(shù)。 CallNonvirtual<type>MethodV()接收所有的參數(shù),并且按照順序?qū)⑺鼈儌鬟f給需要調(diào)用的Java方法。
將上面這系列方法展開如下:
CallNonvirtual<type>Method Routine Name Native Type
CallNonvirtualVoidMethod()
CallNonvirtualVoidMethodA() void
CallNonvirtualVoidMethodV()
CallNonvirtualObjectMethod()
CallNonvirtualObjectMethodA() jobject
CallNonvirtualObjectMethodV()
CallNonvirtualBooleanMethod()
CallNonvirtualBooleanMethodA() jboolean
CallNonvirtualBooleanMethodV()
CallNonvirtualByteMethod()
CallNonvirtualByteMethodA() jbyte
CallNonvirtualByteMethodV()
CallNonvirtualCharMethod()
CallNonvirtualCharMethodA() jchar
CallNonvirtualCharMethodV()
CallNonvirtualShortMethod()
CallNonvirtualShortMethodA() jshort
CallNonvirtualShortMethodV()
CallNonvirtualIntMethod()
CallNonvirtualIntMethodA() jint
CallNonvirtualIntMethodV()
CallNonvirtualLongMethod()
CallNonvirtualLongMethodA() jlong
CallNonvirtualLongMethodV()
CallNonvirtualFloatMethod()
CallNonvirtualFloatMethodA() jfloat
CallNonvirtualFloatMethodV()
CallNonvirtualDoubleMethod()
CallNonvirtualDoubleMethodA() jdouble
CallNonvirtualDoubleMethodV()
參數(shù)解釋:
- env:JNI接口指針
- obj:Java對(duì)象
- clazz:Java類
- methodID:方法ID
返回:
調(diào)用Java方法的結(jié)果
拋出異常:
在Java方法中執(zhí)行過程可能產(chǎn)生的異常
(十三)、獲取靜態(tài)屬性
jfieldID GetStaticFieldID(JNIEnv *env,jclass clazz,const char* name,const char *sig);
獲取某個(gè)類的某個(gè)靜態(tài)屬性ID,根據(jù)屬性名以及標(biāo)簽來確定是哪個(gè)屬性。GetStaticField()和SetStaticField()通過使用屬性ID來對(duì)屬性進(jìn)行操作的。如果這個(gè)類還沒有初始化,直接調(diào)用GetStaticFieldID()會(huì)引起這個(gè)類進(jìn)行初始化。
參數(shù)解釋:
- env:JNI接口指針
- clazz:Java類
- name:靜態(tài)屬性的屬性名,是一個(gè)編碼格式"utf-8"并且以0結(jié)尾的字符串。
- sig:屬性的簽名,是一個(gè)編碼格式"utf-8"并且以0結(jié)尾的字符串。
返回:
返回靜態(tài)屬性ID,如果指定的靜態(tài)屬性無法找則返回NULL
異常:
如果指定的靜態(tài)屬性無法找到則拋出NoSuchFieldError
如果類在初始化失敗,則拋出ExceptionInInitializerError
如果內(nèi)存不夠,則拋出OutOfMemoryError
(十四)、獲取靜態(tài)屬性系列
NativeType GetStatic<type>Field(JNIEnv *env,jclass clazz,jfieldID fieldID);
這個(gè)系列返回一個(gè)對(duì)象的靜態(tài)屬性的值??梢酝ㄟ^GetStaticFieldID()來獲取靜態(tài)屬性的的ID,有了這個(gè)ID,我們就可以獲取這個(gè)對(duì)其進(jìn)行操作了
下面表明了函數(shù)名和函數(shù)的返回值,所以只需要替換GetStatic<type>Field中的類替換為該字段的Java類型或者表中的實(shí)際靜態(tài)字段存取器。并將NativeType替換為相應(yīng)的本地類型
GetStatic<type>Field Routine Name Native Type
GetStaticObjectField() jobject
GetStaticBooleanField() jboolean
GetStaticByteField() jbyte
GetStaticCharField() jchar
GetStaticShortField() jshort
GetStaticIntField() jint
GetStaticLongField() jlong
GetStaticFloatField() jfloat
GetStaticDoubleField() jdouble
參數(shù)解釋:
- env:JNI接口指針
- clazz:Java類
- field:靜態(tài)屬性ID
返回:
返回靜態(tài)屬性
(十五)、設(shè)置靜態(tài)屬性系列
void SetStatic<type>Field(JNIEnv *env,jclass clazz,jfieldID fieldID,NativeType value);
這個(gè)系列是設(shè)置類的靜態(tài)屬性的值。可以通過GetStaticFieldID()來獲取靜態(tài)屬性的ID。
下面詳細(xì)介紹了函數(shù)名和其值,你可以通過SetStatic<type>并傳入的NativeType來設(shè)置Java中的靜態(tài)屬性。
SetStatic<type>Field Routine Name NativeType
SetStaticObjectField() jobject
SetStaticBooleanField() jboolean
SetStaticByteField() jbyte
SetStaticCharField() jchar
SetStaticShortField() jshort
SetStaticIntField() jint
SetStaticLongField() jlong
SetStaticFloatField() jfloat
SetStaticDoubleField() jdouble
參數(shù)解釋:
- env:JNI接口指針
- clazz:Java類
- field:靜態(tài)屬性ID
- value:設(shè)置的值
(十六)、獲取靜態(tài)函數(shù)ID
jmethodID GetStaticMethodID(JNIEnv *env,jclass clazz,const char *name,const char sig);
返回類的靜態(tài)方法ID,通過它的方法名以及簽名來確定哪個(gè)方法。如果這個(gè)類還沒被初始化,調(diào)用GetStaticMethodID()將會(huì)導(dǎo)致這個(gè)類初始化。
參數(shù)解釋:
- env:JNI接口指針
- clazz:Java類
- name:靜態(tài)方法的方法名,以"utf-8"編碼的,并且以0結(jié)尾的字符串
- sig:方法簽名,以"utf-8"編碼的,并且以0結(jié)尾的字符串
返回:
返回方法ID,如果操作失敗,則返回NULL
異常:
如果沒有找到對(duì)應(yīng)的靜態(tài)方法,則拋出NoSuchMethodError
如果類初始化失敗,則拋出ExceptionInInitializerError
如果系統(tǒng)內(nèi)存不足,則拋出OutOfMemoryError
(十七)、調(diào)用靜態(tài)函數(shù)系列
NativeType CallStatic<type>Method(JNIEnv *env,jclass clazz,jmethodID methodID,...);
NativeType CallStatic<type>MethodA(JNIEnv *env,jclass clazz,jmethodID methodID,... jvalue *args);
NativeType CallStatic<type>MethodV(JNIEnv *env,jclass,jmethodID methodid, va_list args)
根據(jù)指定的方法ID,就可以操作Java對(duì)象的靜態(tài)方法了。可以通過GetStaticMethodID()來獲得methodID。方法的ID必須是clazz的,而不是其父類的方法ID。
下面就是詳細(xì)的方法了
CallStatic<type>Method Routine Name Native Type
CallStaticVoidMethod()
CallStaticVoidMethodA() void
CallStaticVoidMethodV()
CallStaticObjectMethod()
CallStaticObjectMethodA() jobject
CallStaticObjectMethodV()
CallStaticBooleanMethod()
CallStaticBooleanMethodA() jboolean
CallStaticBooleanMethodV()
CallStaticByteMethod()
CallStaticByteMethodA() jbyte
CallStaticByteMethodV()
CallStaticCharMethod()
CallStaticCharMethodA() jchar
CallStaticCharMethodV()
CallStaticShortMethod()
CallStaticShortMethodA() jshort
CallStaticShortMethodV()
CallStaticIntMethod()
CallStaticIntMethodA() jint
CallStaticIntMethodV()
CallStaticLongMethod()
CallStaticLongMethodA() jlong
CallStaticLongMethodV()
CallStaticFloatMethod()
CallStaticFloatMethodA() jfloat
CallStaticFloatMethodV()
CallStaticDoubleMethod()
CallStaticDoubleMethodA() jdouble
CallStaticDoubleMethodV()
參數(shù)解釋:
- env:JNI接口指針
- clazz:Java類
- methodID:靜態(tài)方法ID
返回:
返回靜態(tài)的Java方法的調(diào)用方法
異常:
在Java方法中執(zhí)行中拋出的異常
七、字符串操作
(一)、創(chuàng)建一個(gè)字符串
jstring NewString(JNIEnv *env,const jchar *unicodeChars,jszie len);
參數(shù)解釋:
- env:JNI接口指針
- unicodeChars:指向Unicode字符串的指針
- len:unicode字符串的長度
返回:
返回一個(gè)Java字符串對(duì)象,如果該字符串無法被創(chuàng)建在,則返回NULL
異常:
如果內(nèi)存不足,則拋出OutOfMemoryError
(二)、獲取字符串的長度
jsize GetStringLength(JNIEnv *env,jstring string);
返回Java字符串的長度(unicode字符的個(gè)數(shù))
參數(shù)解釋:
- env:JNI接口指針
- string:Java字符串對(duì)象
返回:
返回Java字符串的長度
(三)、獲取字符串的指針
const jchar* GetStringChar(JNIEnv *env,jstring string , jboolean *isCopy);
返回指向字符串的UNICODE字符數(shù)組的指針,該指針一直有效直到被ReleaseStringchars()函數(shù)調(diào)用。
如果isCopy為非空,則在復(fù)制完成后將isCopy設(shè)為JNI_TRUE。如果沒有復(fù)制,則設(shè)為JNI_FALSE。
參數(shù)解釋:
- env:JNI接口指針
- string:Java字符串對(duì)象
- isCopy:指向布爾值的指針
返回:
返回一個(gè)指向unicode字符串的指針,如果操作失敗,則返回NULL
(四)、釋放字符串
void ReleaseStringChars(JNIEnv *env,jstring string,const jchar *chars);
通過VM,native代碼不會(huì)再訪問chars了。參數(shù)chars是一個(gè)指針。可以通過GetStringChars()函數(shù)獲得。
參數(shù)解釋:
- env:JNI接口指針
- string:Java字符串對(duì)象
- chars:指向Unicode字符串的指針
(五)、創(chuàng)建一個(gè)UTF-8的字符串
jstring NewStringUTF(JNIEnv *env,const char *bytes);
創(chuàng)建一個(gè)UTF-8的字符串。
參數(shù)解釋:
- env:JNI接口指針
- bytes:指向UTF-8字符串的指針
返回:
Java字符串對(duì)象,如果無法構(gòu)造該字符串,則為NULL。
異常:
如果系統(tǒng)內(nèi)存不足,則拋出OutOfMemoryError
(六)、獲取一個(gè)UTF-8的字符串的長度
jsize GetStringUTFLength(JNIEnv *env,jstring string);
以字節(jié)為單位,返回字符串UTF-8的長度。
參數(shù)解釋:
- env:JNI接口指針
- String:Java字符串對(duì)象
返回:
字符串的UTF-8的長度
(七)、獲取StringUTFChars的指針
const char *GetStringUFTChars(JNIEnv *env, jString string, jboolean *isCopy);
返回指向UTF-8字符數(shù)組的指針,除非該數(shù)組被ReleaseStringUTFChars()函數(shù)調(diào)用釋放,否則一直有效。
如果isCopy不是NULL,*isCopy在賦值完成后即被設(shè)置為JNI_TRUE。如果未復(fù)制,則設(shè)置為JNI_FALSE。
參數(shù)解釋:
- env:JNI接口指針
- String:Java字符串對(duì)象
- isCopy:指向布爾值的指針
返回:
指向UTF-8的字符串指針,如果操作是啊白,則返回NULL
(八)、釋放UTFChars
void ReleaseStringUTFChars(JNIEnv *env,jstring string,const char *urf)
通過虛擬機(jī),native代碼不再訪問了utf了。utf是一個(gè)指針,可以調(diào)用GetStringUTFChars()獲取。
參數(shù)解釋:
- env:JNI接口指針
- string:Java字符串對(duì)象
- utf:指向utf-8字符串的指針
注意:在JDK/JRE 1.1,程序員可以在用戶提供的緩沖區(qū)獲取基本類型數(shù)組元素,從JDK/JRE1.2開始,提供了額外方法,這些方法允許在用戶提供的緩沖區(qū)獲取Unicode字符(UTF-16編碼)或者是UTF-8的字符。這些方法如下:
(九)、1.2新的字符串操作方法
1 截取一個(gè)字符串
void GetStringRegion(JNIEnv *env,jstring str,jsize start,jsize len,jchar *buf)
在str(Unicode字符)從start位置開始截取len長度放置在buf中。如果越界,則拋出StringIndexOutOfBoundsException。
2 截取一個(gè)字符串并將其轉(zhuǎn)換為UTF-8格式
void GetStringUTFRegion(JNIEnv *env,jstring str,jsize start ,jsize len,char *buf);
將str(Unicode字符串)從start位置開始截取len長度并且將其轉(zhuǎn)換為UTF-8編碼,然后將結(jié)果防止在buf中。
3 截取一個(gè)字符串并將其轉(zhuǎn)換為UTF-8格式
const jchar * GetStringCritical(JNIEnv *env,jstring string,jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env,jstring string,cost jchar * carray);
上面這兩個(gè)函數(shù)有點(diǎn)類似于GetStringChars()和ReleaseStringChars()功能。如果可能的話虛擬機(jī)會(huì)返回一個(gè)指向字符串元素的指針;否則,則返回一個(gè)復(fù)制的副本。
PS:
GetStringChars()和ReleaseStringChars()這里兩個(gè)函數(shù)有很大的限制。在使用這兩個(gè)函數(shù)時(shí),這兩個(gè)函數(shù)中間的代碼不能調(diào)用任何讓線程阻塞或者等待JVM的其他線程的本地函數(shù)或者JNI函數(shù)。有了這些限制,JVM就可以在本地方法持有一個(gè)從GetStringCritical得到的字符串的指指針時(shí),禁止GC。當(dāng)GC被禁止時(shí),任何線程如果出發(fā)GC的話,都會(huì)被阻塞。而GetStringChars()和ReleaseStringChars()這兩個(gè)函數(shù)中間的任何本地代碼都不可以執(zhí)行會(huì)導(dǎo)致阻塞的調(diào)用或者為新對(duì)象在JVM中分配內(nèi)存。否則,JVM有可能死活,想象一下這樣的場景:
- 1、只有當(dāng)前線程觸發(fā)的GC完成阻塞并釋放GC時(shí),由其他線程出發(fā)的GC才可能由阻塞中釋放出來繼續(xù)執(zhí)行。
- 2、在這個(gè)過程中,當(dāng)前線程會(huì)一直阻塞,因?yàn)槿魏巫枞哉{(diào)用都需要獲取一個(gè)正在被其他線程持有的鎖,而其他線程正等待GC。
GetStringChars()和ReleaseStringChars()的交替迭代調(diào)用是安全的,這種情況下,它們的使用必須有嚴(yán)格的順序限制。而且,我們一定要記住檢查是否因?yàn)閮?nèi)存溢出而導(dǎo)致它的返回值是NULL。因?yàn)镴VM在執(zhí)行GetStringChars()這個(gè)函數(shù)時(shí),仍有發(fā)生數(shù)據(jù)復(fù)制的可能性,尤其是當(dāng)JVM在內(nèi)存存儲(chǔ)的數(shù)組不連續(xù)時(shí),為了返回一個(gè)指向連續(xù)內(nèi)存空間的指針,JVM必須復(fù)制所有數(shù)據(jù)。
總之,為了避免死鎖,在GetStringChars()和ReleaseStringChars()`之間不要調(diào)用任何JNI函數(shù)。
八、數(shù)組操作
(一)、獲取數(shù)組的長度
jsize GetArrayLength(JNIEnv *env,jarray array)
返回?cái)?shù)組的長度
參數(shù)解釋:
- env:JNI接口指針
- array:Java數(shù)組
返回:
數(shù)組的長度
(二)、創(chuàng)建對(duì)象數(shù)組
jobjectArray NewObjectArray(JNIEnv *env,jsize length,jclass elementClass, jobject initialElement);
創(chuàng)建一個(gè)新的對(duì)象數(shù)組,它的元素的類型是elementClass,并且所有元素的默認(rèn)值是initialElement。
參數(shù)解釋:
- env:JNI接口指針
- length:數(shù)組大小
- elementClass:數(shù)組元素類
- initialElement:數(shù)組元素的初始值
返回:
Java數(shù)組對(duì)象,如果無法構(gòu)造數(shù)組,則返回NULL
異常:
如果內(nèi)存不足,則拋出OutOfMemoryError
(三)、獲取數(shù)組元中的某個(gè)元素
jobject GetObjectArrayElement(JNIEnv *env,jobjectArray array,jsize index);
返回元素中某個(gè)位置的元素
參數(shù)解釋:
- env:JNI接口指針
- array:Java數(shù)組
- index:數(shù)組下標(biāo)
返回:
Java對(duì)象
異常:
如果index下標(biāo)不是一個(gè)有效的下標(biāo),則會(huì)拋出ArrayIndexOutOfBoundsException
(四)、設(shè)置數(shù)組中某個(gè)元素的值
void SetObjectArrayElement(JNIEnv *env,jobjectArray array,jsize index,jobject value);
設(shè)置下標(biāo)為index元素的值。
參數(shù)解釋:
- env:JNI接口指針
- array:Java數(shù)組
- index:數(shù)組下標(biāo)
- value:數(shù)組元素的新值
異常:
如果index不是有效下標(biāo),則會(huì)拋出ArrayIndexOutOfBoundsException
如果value不是元素類的子類,則會(huì)拋出ArrayStoreException
(五)、創(chuàng)建基本類型數(shù)組系列
ArrayType New<PrimitiveType>Array(JNIEnv *env,jsize length);
用于構(gòu)造基本類型數(shù)組對(duì)象的一系列操作。下面說明了特定基本類型數(shù)組的創(chuàng)建函數(shù)??梢园袾ew<PrimitiveType>Array替換為某個(gè)實(shí)際的基本類型數(shù)組創(chuàng)建函數(shù) ,然后將ArrayType替換為相應(yīng)的數(shù)組類型
New<PrimitiveType>Array Routines Array Type
NewBooleanArray() jbooleanArray
NewByteArray() jbyteArray
NewCharArray() jcharArray
NewShortArray() jshortArray
NewIntArray() jintArray
NewLongArray() jlongArray
NewFloatArray() jfloatArray
NewDoubleArray() jdoubleArray
參數(shù)解釋:
- env:JNI接口指針
- length:數(shù)組長度
返回:
Java數(shù)組,如果無法創(chuàng)建該數(shù)組,則返回NULL。
(六)、獲取基本類型數(shù)組的中數(shù)組指針系列
NativeType * Get<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array,jboolean * isCopy);
一組返回類型是基本類型的數(shù)組指針。在調(diào)用相應(yīng)的Release<PrimitiveType>ArrayElements()函數(shù)前將一直有效。由于返回的數(shù)組可能是Java數(shù)組的副本,因此,對(duì)返回?cái)?shù)組的變更沒有在基本類型中反應(yīng)出來。除非了調(diào)用
一組返回基本類型數(shù)組體的函數(shù)。結(jié)果在調(diào)用相應(yīng)的 Release<PrimitiveType>ArrayElements()函數(shù)前將一直有效。由于返回的數(shù)組可能是 Java 數(shù)組的副本,因此對(duì)返回?cái)?shù)組的更改不必在基本類型數(shù)組中反映出來,直到調(diào)用``Release<PrimitiveType>ArrayElements()`函數(shù)。
如果isCopy不是NULL,*isCopy在復(fù)制完成后即被設(shè)為JNI_TRUE。如果未復(fù)制,則設(shè)為JNI_FALSE。
下面說明了特定的基本類型數(shù)組元素的具體函數(shù):
- 將
Get<PrimitiveType>ArrayElements替換為表中某個(gè)實(shí)際的基本> 類型的函數(shù)- 將ArrayType替換為對(duì)應(yīng)的數(shù)組類型
- 將NativeType替換為本地變量
不管布爾數(shù)組在Java虛擬機(jī)總?cè)绾伪硎荆?code>GetBooleanArrayElements()將始終返回一個(gè)jboolean類型的指針,其中每一個(gè)字節(jié)代表一個(gè)元素(開包表示)。內(nèi)存中將確保所有其他類型的數(shù)組為連續(xù)的。
Get<PrimitiveType>ArrayElements Routines Array Type Native Type
GetBooleanArrayElements() jbooleanArray jboolean
GetByteArrayElements() jbyteArray jbyte
GetCharArrayElements() jcharArray jchar
GetShortArrayElements() jshortArray jshort
GetIntArrayElements() jintArray jint
GetLongArrayElements() jlongArray jlong
GetFloatArrayElements() jfloatArray jfloat
GetDoubleArrayElements() jdoubleArray jdouble
參數(shù)解釋:
- env:JNI接口指針
- array:Java數(shù)組
- isCopy:指向布爾值的指針
返回:
返回指向數(shù)組元素的指針,如果操作失敗,則返回NULL
(七)、釋放基本類型的數(shù)組系列
void Release<PrimitiveType>ArrayElements(JNIEnv *env,ArrayType array,NativeType *elems,jint mode);
通知虛擬機(jī)Native不再訪問數(shù)組的元素了。elems參數(shù)是使用相應(yīng)的Get <PrimitiveType> ArrayElements()函數(shù)數(shù)組范返回的指針。如果有需要的話,該函數(shù)復(fù)制復(fù)制所有的elems上的變換到原始數(shù)組元素上去。mode參數(shù)提供了數(shù)組buffer應(yīng)該怎么被釋放。如果elems不是被array的一個(gè)副本,mode并沒有什么影響。否則
果需要,該函數(shù)復(fù)制所有的在elems上的變換到原始的數(shù)組元素上去。
mode參數(shù)提供了數(shù)組buffer應(yīng)該怎樣被釋放。如果elems不是array的一個(gè)副本,mode并沒有什么影響。
mode的取值 有如下3種情況:
- 0:復(fù)制內(nèi)容并釋放elems緩沖區(qū)
- JNI_COMMIT:復(fù)制內(nèi)容但不釋放elems緩沖區(qū)
- JNI_ABORT:釋放緩沖區(qū)而不復(fù)制可能的更改
大多數(shù)情況下,程序員將“0”作為參數(shù)傳遞,因?yàn)檫@樣可以確保固定和復(fù)制數(shù)組的一致行為。其他選項(xiàng)可以讓程序員更好的控制內(nèi)存。
下面說明了特定的基本類型數(shù)組元素的具體函數(shù):
- 將
Release <PrimitiveType> ArrayElements替換下面中某個(gè)實(shí)際的基本> 類型的函數(shù)- 將ArrayType替換為對(duì)應(yīng)的基本數(shù)組類型
- 將NativeType替換為本地變量
下面描述了基本類型數(shù)組釋放的詳情。 您應(yīng)該進(jìn)行以下替換:
Release<PrimitiveType>ArrayElements Routines Array Type Native Type
ReleaseBooleanArrayElements() jbooleanArray jboolean
ReleaseByteArrayElements() jbyteArray jbyte
ReleaseCharArrayElements() jcharArray jchar
ReleaseShortArrayElements() jshortArray jshort
ReleaseIntArrayElements() jintArray jint
ReleaseLongArrayElements() jlongArray jlong
ReleaseFloatArrayElements() jfloatArray jfloat
ReleaseDoubleArrayElements() jdoubleArray jdouble
參數(shù)解釋:
- env:JNI接口指針
- array:Java數(shù)組
- elems:指向基本類型的數(shù)組的指針
- mode:釋放模式
(八)、復(fù)制過去基本類型的數(shù)組系列
void Get<PrimitiveType> ArrayRegion(JNIEnv *env,ArrayType array,jsize start,jsize len,NativeType *buf);
復(fù)制基本類型的數(shù)組給buff
下面說明了特定的基本類型數(shù)組元素的具體函數(shù):
- 將
Get<PrimitiveType> ArrayRegion替換下面中某個(gè)實(shí)際的基本> 類型的函數(shù)- 將ArrayType替換為對(duì)應(yīng)的基本數(shù)組類型
- 將NativeType替換為本地變量
Get<PrimitiveType>ArrayRegion Routine Array Type Native Type
GetBooleanArrayRegion() jbooleanArray jboolean
GetByteArrayRegion() jbyteArray jbyte
GetCharArrayRegion() jcharArray jchar
GetShortArrayRegion() jshortArray jhort
GetIntArrayRegion() jintArray jint
GetLongArrayRegion() jlongArray jlong
GetFloatArrayRegion() jfloatArray jloat
GetDoubleArrayRegion() jdoubleArray jdouble
參數(shù)解釋:
- env:JNI接口指針
- array:Java數(shù)組
- start:開始索引
- len:需要復(fù)制的長度
- buf:目標(biāo)buffer
異常:
如果索引無效,則拋出ArrayIndexOutOfBoundsException
(九)、把基本類型數(shù)組的數(shù)組復(fù)制回來系列
void Set<PrimitiveType> ArrayRegion(JNIEnv *env,ArrayType array,jsize start,jsize len,const NativeType *buf);
主要是沖緩沖區(qū)復(fù)制基本類型的數(shù)組的函數(shù)
下面說明了特定的基本類型數(shù)組元素的具體函數(shù):
- 將
Set<PrimitiveType>ArrayRegion替換下面中某個(gè)實(shí)際的基本> 類型的函數(shù)- 將ArrayType替換為對(duì)應(yīng)的基本數(shù)組類型
- 將NativeType替換為本地變量
Set<PrimitiveType>ArrayRegion Routine Array Type Native Type
SetBooleanArrayRegion() jbooleanArray jboolean
SetByteArrayRegion() jbyteArray jbyte
SetCharArrayRegion() jcharArray jchar
SetShortArrayRegion() jshortArray jshort
SetIntArrayRegion() jintArray jint
SetLongArrayRegion() jlongArray jlong
SetFloatArrayRegion() jfloatArray jfloat
SetDoubleArrayRegion() jdoubleArray jdouble
參數(shù)解釋:
- env:JNI接口指針
- array:Java數(shù)組
- start:開始索引
- len:需要復(fù)制的長度
- buf:源buffer
異常:
如果索引無效則會(huì)拋出ArrayIndexOutOfBoundsException
(十)、補(bǔ)充
從JDK/JER 1.1開始提供
Get/Release<primitivetype>ArrayElements函數(shù)獲取指向原始數(shù)組元素的指針。如果VM支持鎖定,則返回指向原始數(shù)組的指針,否則,復(fù)制。
從JDK/JRE 1.3 開始引入新的功能即便VM不支持鎖定,本地代碼也可以獲取數(shù)組元素的直接指針,
void *GetPrimitiveArrayCritical(JNIEnv *env,jarray array,jboolean *isCopy);
void ReleasePrimitiveArrayCritical(JNIEnv *env,jarray array,void *carray,jint mode);
雖然這兩個(gè)函數(shù)與上面的Get/Release <primitivetype> ArrayElements函數(shù)很像,但是在使用這個(gè)功能的時(shí)候,還是有很多的限制。
在調(diào)用GetPrimitiveArrayCritical之后,調(diào)用ReleasePrimitiveArrayCritical之前,這個(gè)區(qū)域是不能調(diào)用其他JNI函數(shù),而且也不能調(diào)用任何可能導(dǎo)致線程阻塞病等待另一個(gè)Java線程的系統(tǒng)調(diào)用。
比如,當(dāng)前線程不能調(diào)用read函數(shù)來讀取,正在被其他所寫入的stream。
九 系統(tǒng)級(jí)別的操作
(一) 注冊方法
jint RegisterNatives(JNIEnv *env,jclass clazz,const JNINativeMethod *methods,jint nMethod);
根據(jù)clazz參數(shù)注冊本地方法,methods參數(shù)制定JNINativeMethod結(jié)構(gòu)數(shù)組,該數(shù)組包含本地方法的名字、簽名及函數(shù)指針。其中名字及簽名是指向編碼為“UTF-8”的指針;nMethod參數(shù)表明數(shù)組中本地方法的個(gè)數(shù)。
這里說下JNINativeMethod這個(gè)結(jié)構(gòu)體
typedef struct {
char *name;
char *signature;
void *fnPtr;
} JNINativeMethod;
參數(shù)解釋:
- env:JNI接口指針
- clazz:Java類對(duì)象
- methods:類中的native方法
- nMethod:類中本地方法的個(gè)數(shù)
返回;
成功返回0,失敗返回負(fù)數(shù)
異常:
如果沒有找到指定的方法或者方法不是本地方法,則拋出NoSuchMethodError。
(二) 注銷方法
jint UnregisterNatives(JNIEnv *env,jclass clazz);
注銷本地方法。類回收之前還沒有被函數(shù)注冊的狀態(tài)。該函數(shù)一般不能再Native代碼中被調(diào)用,它為特定的程序提供了一種重加載重鏈接本地庫的方法。
參數(shù)解釋:
- JNI:接口指針
- clazz:Java類對(duì)象
返回:
注銷成功返回0,失敗返回負(fù)數(shù)
(三) 監(jiān)視操作
jint MonitorEnter(JNIEnv *env,jobject obj);
obj引用的底層Java對(duì)象關(guān)聯(lián)的監(jiān)視器。obj引用不能為空。每個(gè)Java對(duì)象都有一個(gè)相關(guān)的監(jiān)視器。如果當(dāng)前線程已經(jīng)有關(guān)聯(lián)到obj的監(jiān)視器,它將添加監(jiān)視器的計(jì)數(shù)器來表示這個(gè)線程進(jìn)入監(jiān)視器的次數(shù)。如果關(guān)聯(lián)至obj的監(jiān)視器不屬于任何線程,那當(dāng)前線程將變成該監(jiān)視器的擁有者,并設(shè)置計(jì)數(shù)器為1,如果其他計(jì)數(shù)器已經(jīng)擁有了這個(gè)監(jiān)視器,當(dāng)前線程將進(jìn)行等待直到監(jiān)視器被釋放,然后再獲得監(jiān)視器的擁有權(quán)。
通過MonitorEnter JNI函數(shù)調(diào)用的監(jiān)視器不能用monitorexitJava虛擬機(jī)指令或者同步方法退出。MonitorEnterJNI函數(shù)調(diào)用和monitorenter Java虛擬機(jī)指令可能用同樣的對(duì)象競爭地進(jìn)入監(jiān)視器。
為了避免死鎖,通過MoniterEnterJNI函數(shù)調(diào)用進(jìn)入的監(jiān)視器必須用MonitorExitJNI調(diào)用退出,除非DetachCurrentThread接口被隱式的調(diào)用來釋放JNI監(jiān)視器
參數(shù)解釋:
- env:JNI接口指針
- obj:普通的Java對(duì)象或類對(duì)象
返回:
成功返回0,失敗返回負(fù)數(shù)
(四) 監(jiān)視器退出
jint MonitorExit(JNIEnv *env,jobject obj);
當(dāng)前線程擁有與該obj關(guān)聯(lián)的監(jiān)視器,線程減少計(jì)數(shù)器的值來指示線程進(jìn)入監(jiān)視器的次數(shù)。如果計(jì)數(shù)器的值變?yōu)?,則線程釋放該監(jiān)視器。Native代碼不能直接調(diào)用MonitorExit來釋放監(jiān)視器。而是應(yīng)該通過同步方法來使用Java虛擬機(jī)指令來釋放監(jiān)視器
參數(shù)解釋:
- env:JNI接口指針
- obj:普通的Java對(duì)象或類對(duì)象
返回:
成功返回0,失敗返回負(fù)數(shù)
異常:
如果當(dāng)前線程不擁有該監(jiān)視器,則應(yīng)該拋出IllegalMonitorStateException
十 NIO操作
NIO相關(guān)操作允許Native代碼直接訪問java.nio的直接緩沖區(qū)。直接緩沖區(qū)的內(nèi)容可能存在于普通的垃圾回收器以外的本地內(nèi)存。有關(guān)直接緩沖區(qū)的信息,可以參考 NIO和java.nio.ByteBuffer類的規(guī)范。
在JDK/JRE 1.4中引入了新的JNI函數(shù),允許檢查和操作做直接緩沖區(qū)
- NewDirectByteBuffer
- GetDirectBufferAddress
- GetDirectBufferCapacity
每個(gè)Java虛擬機(jī)的實(shí)現(xiàn)都必須支持這些功能,但并不是每個(gè)實(shí)現(xiàn)都需要支持對(duì)直接緩沖區(qū)的JNI訪問。如果JVM不支持這種訪問,那么NewDirectByteBuffer和GetDirectBufferAddress函數(shù)必須始終返回NULL,并且GetDirectBufferCapacity函數(shù)必須始終返回-1。如果JVM確實(shí)支持這種訪問,那么必須實(shí)現(xiàn)這三個(gè)函數(shù)才能返回合適的值。
(一) 返回ByteBuffer
jobject NewDirectByteBuffer(JNIEnv *env,void *address,jlong capacity);
分配并返回一個(gè)直接的java.nio.ByteBuffer內(nèi)存塊從內(nèi)存地址address開始的capacity個(gè)字節(jié).
調(diào)用這個(gè)函數(shù)并返回字節(jié)緩沖區(qū)的對(duì)象的Native代碼必須保證緩沖區(qū)指向一個(gè)可靠的可被讀寫的內(nèi)存區(qū)域。進(jìn)入非法的內(nèi)存位置有可能會(huì)返回任意數(shù)值,DNA不會(huì)有明顯的印象,也有可能拋出異常。
參數(shù)解釋:
- env:JNIEnv接口指針
- address:內(nèi)存區(qū)域的起始地址
- capacity:內(nèi)存區(qū)域的大小
返回:
返回一個(gè)新開辟的java.nio.ByteBuffer對(duì)象的本地引用。如果產(chǎn)生異常,則返回NULL。如果JVM不支持JNI訪問直接緩沖區(qū),也會(huì)返回NULL
異常:
如果緩沖區(qū)分配失敗,則返回OutOfMemoryError
(二) 返回直接緩沖區(qū)中對(duì)象的初始地址
void* GetDirectBufferAddress(JNIEnv *env,jobject buf);
獲取并返回java.nio.Buffer的內(nèi)存初始地址
該函數(shù)允許Native代碼通過直接緩沖區(qū)對(duì)象訪問Java代碼的同一內(nèi)存區(qū)域
參數(shù)解釋:
- env:JNIEnv接口指針
- buf:java.nio.Buffer對(duì)象
返回:
返回內(nèi)存區(qū)域的初始地址。如果內(nèi)存區(qū)域未定義,返回NULL,如果給定的對(duì)象不是java.nio.buffer,則返回NULL,如果虛擬機(jī)不支持JNI訪問,則返回NULL。
(三) 返回直接緩沖區(qū)中對(duì)象的內(nèi)存容量
jlong GetDirectBufferCapacity(JNIEnv *env,jobject buf);
獲取并返回java.nio.Buffer的內(nèi)存容量。該容量是內(nèi)存區(qū)域可容納的元素的個(gè)數(shù)
參數(shù):
- env:JNIEnv接口指針
- buf:java.nio.Buffer對(duì)象
返回:
返回內(nèi)存區(qū)域的容量。如果指定的對(duì)象不是java.nio.buffer,則返回-1,或者如果對(duì)象是未對(duì)齊的view buffer且處理器架構(gòu)不支持對(duì)齊訪問。如果虛擬機(jī)不支持JNI訪問則返回-1。
十一、反射支持
如果程序員知道方法和屬性的名稱和類型,則直接使用JNI調(diào)用Java方法或者訪問Java字段。Java核心反射API允許在運(yùn)行時(shí)反射Java類。JNI提供了JNI中使用的字段和方法ID與Java Core Reflection API中使用的字段和方法對(duì)象之間的一組轉(zhuǎn)換函數(shù)。
(一)、轉(zhuǎn)化獲取方法ID
jmethodID FromReflectedMethod(JNIEnv *env,jobject method);
將java.lang.reflect.Method或者java.lang.reflect.Constructor對(duì)象轉(zhuǎn)換為方法ID
參數(shù)解釋:
- env:JNIEnv接口指針
- method:java.lang.reflect.Method或者java.lang.reflect.Constructor對(duì)象
返回:
方法ID
(二)、轉(zhuǎn)化獲取屬性ID
jfield FromReflectedField(JNIEnv *env,jobject field);
將java.lang.reflect.Field轉(zhuǎn)化域ID
參數(shù)解釋:
- env:JNIEnv接口指針
- field:java.lang.reflect.Field對(duì)象
返回:
域ID
(三)、反轉(zhuǎn)化并獲取方法對(duì)象
jobject ToReflectedMethod(JNIEnv *env,jclass clazz,jmethodID methodID, jboolean isStatic);
將源自cls的方法ID轉(zhuǎn)化為java.lang.reflect.Method或者java.lang.reflect.Constructor對(duì)象。如果方法ID指向一個(gè)靜態(tài)屬性,isStatic必須設(shè)置為JNI_TRUE,否則為JNI_FALSE。
參數(shù)解釋:
- env:JNIEnv接口指針
- clazz:Java類對(duì)象
- methodID:Java類對(duì)應(yīng)的方法id
- isStatic:是否是靜態(tài)方法
返回
對(duì)應(yīng)Java層 java.lang.reflect.Method或者java.lang.reflect.Constructor對(duì)象。如果失敗,則返回0
異常:
如果內(nèi)存不足,則拋出OutOfMemoryError。
(四)、反轉(zhuǎn)化并獲取屬性對(duì)象
jobject ToReflectedField(JNIEnv *env,jclass cls,jfieldID field,jboolean isStatic)
將來源于cls的屬性ID轉(zhuǎn)化為java.lang.reflect.Field對(duì)象。如果屬性ID指向一個(gè)靜態(tài)屬性,isStatic必須設(shè)置為JNI_TRUE,否則為JNI_FALSE。
參數(shù)解釋:
- env:JNIEnv接口指針
- cls:Java類對(duì)象
- methodID:Java對(duì)應(yīng)的屬性ID
- isStatic:是否是靜態(tài)屬性
返回:
成功返回java.lang.reflect.Field對(duì)象,失敗返回0
異常:
如果內(nèi)存不足,則拋出OutOfMemoryError
十二、獲取虛擬機(jī)
jint GetJavaVM(JNIEnv *env,JavaVM **vm);
返回當(dāng)前線程對(duì)應(yīng)的java虛擬機(jī)接口。返回的結(jié)果保存在vm。
參數(shù)解釋:
- env:JNI接口指針
- vm:保存虛擬機(jī)指針
返回:
成功返回0,失敗返回負(fù)數(shù)
上一篇文章Android JNI學(xué)習(xí)(三)——Java與Native相互調(diào)用
下一篇文章Android JNI學(xué)習(xí)(五)——Demo演示