利用JNIEnv自變量,程序員可訪問一系列函數(shù)。這些函數(shù)可劃分為下述類別:
■獲取版本信息
■進(jìn)行類和對(duì)象操作
■控制對(duì)java對(duì)象的全局和局部引用
■訪問實(shí)例字段和靜態(tài)字段
■調(diào)用實(shí)例方法和靜態(tài)方法
■執(zhí)行字串和數(shù)組操作
■產(chǎn)生和控制Java異常
 
獲取版本信息
jint GetVersion(JNIEnv *env);
 
獲取JNI函數(shù)版本信息,
返回值為jint類型,在c/c++中jint為32位數(shù),其中高16位是主版本號(hào),低16位是從版本號(hào)
In JDK/JRE 1.1, GetVersion() returns 0x00010001.
In JDK/JRE 1.2, GetVersion() returns 0x00010002.
In JDK/JRE 1.4, GetVersion() returns 0x00010004.
jclass FindClass(JNIEnv *env, const char *name);
 
在CLASSPATH 環(huán)境變量中搜索目錄和zip 文件中具有指定名稱的類。
 
參數(shù):
name: a fully-qualified class name /”隔開
SINCE JDK/JRE 1.2:
 
產(chǎn)生和控制Java異常
 
jint Throw(JNIEnv *env, jthrowable obj);
 
拋出異常
 
參數(shù):jthrowable  java.lang.Throwable 包中對(duì)象.
 
jint ThrowNew(JNIEnv *env, jclass clazz,const char *message);
 
通過消息構(gòu)造一個(gè)異常類,其中參數(shù)clazz 為 java.lang.Throwable包中的子類
 
jthrowable ExceptionOccurred(JNIEnv *env);
 
測(cè)試JVM是否有異常發(fā)生
 
SINCE JDK/JRE 1.2:
 
 
local reference 和 global reference。
 
Java 和JNI代碼之間函數(shù)調(diào)用時(shí),簡單類型,也就是內(nèi)置類型,比如 int, char 等是值傳遞(pass by value),而其它 Java 對(duì)象都是引用傳遞(pass by reference),這些對(duì)象引用由 JVM 傳給JNI代碼,每個(gè)都有其生命周期。
 
JNI 函數(shù)參數(shù)中 jobject 或者它的子類,其參數(shù)都是 local reference。Local reference 只在這個(gè) JNI函數(shù)中有效,JNI函數(shù)返回后,引用的對(duì)象就被釋放,它的生命周期就結(jié)束了。若要留著日后使用,則需根據(jù)這個(gè) local reference 創(chuàng)建 global reference。Global reference 不會(huì)被系統(tǒng)自動(dòng)釋放,它僅當(dāng)被程序明確調(diào)用 DeleteGlobalReference 時(shí)才被回收。(JNI多線程機(jī)制)
 
jobject NewGlobalRef(JNIEnv *env, jobject obj);
 
創(chuàng)建一個(gè)新的全局的引用,只能使用DeleteGlobalRef()函數(shù)銷毀這個(gè)全局引用
參數(shù):
Obj 一個(gè)本地引用或者全局引用
 
void DeleteGlobalRef(JNIEnv *env, jobject globalRef);
 
銷毀全局引用
參數(shù):
globalRef 使用NewGlobalRef()函數(shù)生成的全局引用
 
 
 
銷毀本地的引用
 
注意:
JDK/JRE 1.1 提供了上面的 DeleteLocalRef 函數(shù),使程序員可以手動(dòng)刪除本地引用。例如,如果本機(jī)代碼遍歷可能很大的對(duì)象或數(shù)組,并使用每個(gè)迭代中的一個(gè)元素,好的做法是下一次迭代中創(chuàng)建一個(gè)新的本地引用之前刪除本地元素的引用。
JDK/JRE 1.2 和更高版本為本地引用生存周期管理提供了一套額外的函數(shù)。他們是下面列出的四種函數(shù)。
jint EnsureLocalCapacity(JNIEnv *env, jint capacity);
通知JVM 您將使用超過 16 個(gè)本地引用。這將允許 JVM 優(yōu)化對(duì)該本機(jī)代碼的本地引用的處理
jint PushLocalFrame(JNIEnv *env, jint capacity);
 
jobject PopLocalFrame(JNIEnv *env, jobject result);
先調(diào)用PushLocalFrame,然后創(chuàng)建局部引用,并對(duì)其進(jìn)行處理,最后調(diào)用PushLocalFrame釋放局部引用,這時(shí)Java虛擬機(jī)也可以對(duì)其指 向的對(duì)象進(jìn)行垃圾回收。可以用C語言的棧來理解這對(duì)JNI API,調(diào)用PushLocalFrame之后Native代碼創(chuàng)建的所有局部引用全部入棧,當(dāng)調(diào)用PopLocalFrame之后,入棧的局部引用除了 需要返回的局部引用(PushLocalFrame和PopLocalFrame這對(duì)函數(shù)可以返回一個(gè)局部引用給外部)之外,全部出棧,Java虛擬機(jī)這 時(shí)可以釋放他們指向的對(duì)象。具體的用法可以參考手冊(cè)。這兩個(gè)函數(shù)使JNI的局部引用由于和C語言的局部變量用法類似,所以強(qiáng)烈推薦使用
jobject NewLocalRef(JNIEnv *env, jobject ref);
1、Java虛擬機(jī)默認(rèn)為Native引用分配的局部引用數(shù)量是有限的,大部分的Java虛擬機(jī)實(shí)現(xiàn)默認(rèn)分配16個(gè)局部引用。當(dāng)然Java虛擬 機(jī)也提供API(PushLocalFrame,EnsureLocalCapacity)讓你申請(qǐng)更多的局部引用數(shù)量(Java虛擬機(jī)不保證你一定能申 請(qǐng)到)。有限的資源當(dāng)然要省著點(diǎn)用,否則將會(huì)被Java虛擬機(jī)無情拋棄(程序崩潰)。JNI編程中,實(shí)現(xiàn)Native代碼時(shí)強(qiáng)烈建議調(diào)用PushLocalFrame,EnsureLocalCapacity來確保Java虛擬機(jī)為你準(zhǔn)備好了局部變量空間。
2、如果你實(shí)現(xiàn)的Native函數(shù)是工具函數(shù),會(huì)被頻繁的調(diào)用。如果你在Native函數(shù)中沒有顯示刪除局部引用,那么每次調(diào)用該函數(shù)Java虛擬機(jī)都會(huì)創(chuàng)建一個(gè)新的局部引用,造成局部引用過多。尤其是該函數(shù)在Native代碼中被頻繁調(diào)用,代碼的控制權(quán)沒有交還給Java虛擬機(jī),所以Java虛擬機(jī)根本沒有機(jī)會(huì)釋放這些局部變量。退一步講,就算該函數(shù)直接返回給Java虛擬機(jī),也不能保證沒有問題,我們不能假設(shè)Native函數(shù)返回Java虛 擬機(jī)之后,Java虛擬機(jī)馬上就會(huì)回收Native函數(shù)中創(chuàng)建的局部引用,依賴于Java虛擬機(jī)實(shí)現(xiàn)。所以我們?cè)趯?shí)現(xiàn)Native函數(shù)時(shí)一定要記著刪除不 必要的局部引用,否則你的程序就有潛在的風(fēng)險(xiǎn),不知道什么時(shí)候就會(huì)爆發(fā)。
3、如果你Native函數(shù)根本就不返回。比如消息循環(huán)函數(shù)——死循環(huán)等待消息,處理消息。如果你不顯示刪除局部引用,很快將會(huì)造成Java虛擬機(jī)的局部引用內(nèi)存溢出。
Weak Global References
全局的弱引用是一種特殊的全局引用,與普通的全局引用不同全局的弱引用允許Java 對(duì)象進(jìn)行垃圾回收,當(dāng)垃圾收集器運(yùn)行時(shí),它將釋放對(duì)象,如果引用的對(duì)象只使用弱引用
jweak NewWeakGlobalRef(JNIEnv *env, jobject obj);
void DeleteWeakGlobalRef(JNIEnv *env, jweak obj);
SINCE JDK/JRE 1.2:
Object Operations
jobject AllocObject(JNIEnv *env, jclass clazz);
分配一個(gè)新的 Java 對(duì)象,而不調(diào)用任何對(duì)象的構(gòu)造函數(shù),僅僅是內(nèi)存創(chuàng)建
jobject NewObject(JNIEnv *env, jclass clazz,jmethodID methodID, ...);
jobject NewObjectA(JNIEnv *env, jclass clazz,jmethodID methodID, jvalue *args);
args: an array of arguments to the constructor.
jobject NewObjectV(JNIEnv *env, jclass clazz,jmethodID methodID, va_list args);
args: a va_list of arguments to the constructor.
分配一個(gè)新的java對(duì)象,調(diào)用指定的構(gòu)造函數(shù),構(gòu)造函數(shù)使用methodID指定
jclass GetObjectClass(JNIEnv *env, jobject obj);
根據(jù)類的引用返回類的類型
jboolean IsInstanceOf(JNIEnv *env, jobject obj,jclass clazz);
測(cè)試類的引用類型,是返回JNI_TRUE 否則 返回JNI_FALSE
jboolean IsSameObject(JNIEnv *env, jobject ref1,jobject ref2);
測(cè)試兩個(gè)引用類型是否指向同一個(gè)空間,是返回JNI_TRUE 否則 返回JNI_FALSE
 
accessing Fields of Objects
jfieldID GetFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
GetFieldID是得到java類中的參數(shù)ID,只能調(diào)用類中聲明為 public的屬性,jfieldID為 Get<type>Field andSet<type>Field 函數(shù)族使用
參數(shù):
Name 屬性在java類中的名字
Sig 類型簽名
Get<type>Field Routines
NativeType Get<type>Field(JNIEnv *env, jobject obj,jfieldID fieldID);
 
| 表 3-3   | 
| Get<type>Field Routine Name | Native Type | 
| 
 | jobject | 
| GetBooleanField() | jboolean | 
| GetByteField() | jbyte | 
| 
 | jchar | 
| 
 | jshort | 
| GetIntField() | jint | 
| 
 | jlong | 
| 
 | jfloat | 
| GetDoubleField() | jdouble | 
獲取java對(duì)象屬性的值
Set<type>Field Routines
void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID,NativeType value);
表 3-4  
| Set<type>Field Routine Name | Native Type | 
| Set | jobject | 
| SetBooleanField() | jboolean | 
| SetByteField() | jbyte | 
| Set | jchar | 
| Set | jshort | 
| SetIntField() | jint | 
| Set | jlong | 
| Set | jfloat | 
| SetDoubleField() | jdouble | 
設(shè)置java對(duì)象屬性的值
jmethodID GetMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
GetMethodID得到j(luò)ava類中方法的ID,它只能調(diào)用類中聲明為 public的方法,jmethodID為Call<type>Method函數(shù)族使用
參數(shù):
Name 方法在java類中的名字
Sig 類型簽名
NativeType Call<type>Method(JNIEnv *env, jobject obj,jmethodID methodID, ...);
NativeType Call<type>MethodA(JNIEnv *env, jobject obj,jmethodID methodID, jvalue *args);
NativeType Call<type>MethodV(JNIEnv *env, jobject obj,jmethodID methodID, va_list args);
| 表 3-5  | 
| Call<type>Method Routine Name | Native Type | 
| CallVoidMethod() CallVoidMethodA() CallVoidMethodV() | void   | 
| CallObjectMethod() CallObjectMethodA() CallObjectMethodV() | jobject   | 
| CallBooleanMethod() CallBooleanMethodA() CallBooleanMethodV() | jboolean   | 
| CallByteMethod() CallByteMethodA() CallByteMethodV() | jbyte   | 
| CallCharMethod() CallCharMethodA() CallCharMethodV() | jchar   | 
| CallShortMethod() CallShortMethodA() CallShortMethodV() | jshort   | 
| CallIntMethod() CallIntMethodA() CallIntMethodV() | jint   | 
| CallLongMethod() CallLongMethodA() CallLongMethodV() | jlong   | 
| CallFloatMethod() CallFloatMethodA() CallFloatMethodV() | jfloat   | 
| CallDoubleMethod() CallDoubleMethodA() CallDoubleMethodV() | jdouble   | 
 
調(diào)用java方法通過jmethodID指定
如果想要調(diào)用一個(gè)對(duì)象的父類方法,而不是子類的這個(gè)方法的話,就可以使用NativeTypeCallNonvirtual<type>Method(JNIEnv *env, jobject obj,jclass clazz, jmethodID methodID, ...);
NativeType CallNonvirtual<type>MethodA(JNIEnv *env, jobject obj,jclass clazz, jmethodID methodID, jvalue *args);
NativeType CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj,jclass clazz, jmethodID methodID, va_list args);
| 表 3-6  | 
| CallNonvirtual <type>Method Routine Name | Native Type | 
| CallNonvirtualVoidMethod CallNonvirtualVoidMethod CallNonvirtualVoidMethod | void   | 
| CallNonvirtualObjectMeth CallNonvirtualObjectMeth CallNonvirtualObjectMeth | jobject   | 
| CallNonvirtualBooleanMet CallNonvirtualBooleanMet CallNonvirtualBooleanMet | jboolean   | 
| CallNonvirtualByteMethod CallNonvirtualByteMethod CallNonvirtualByteMethod | jbyte   | 
| CallNonvirtualCharMethod CallNonvirtualCharMethod CallNonvirtualCharMethod | jchar   | 
| CallNonvirtualShortMetho CallNonvirtualShortMetho CallNonvirtualShortMetho | jshort   | 
| CallNonvirtualIntMethod() CallNonvirtualIntMethodA CallNonvirtualIntMethodV | jint   | 
| CallNonvirtualLongMethod CallNonvirtualLongMethod CallNonvirtualLongMethod | jlong   | 
| CallNonvirtualFloatMetho CallNonvirtualFloatMetho CallNonvirtualFloatMetho | jfloat   | 
| CallNonvirtualDoubleMeth CallNonvirtualDoubleMeth CallNonvirtualDoubleMeth | jdouble   | 
例:
package com.cn; 
1. 
2. 
3. 
4. 
5. 
6. 
 
 
 
 
 
jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
GetStaticFieldID得到j(luò)ava類中static 屬性ID,jfieldID為GetStatic<type>Field and SetStatic<type>Field函數(shù)族使用
參數(shù):
clazz java類對(duì)象
name 方法在java類中的名字
sig  類型簽名
 
GetStatic<type>Field Routines
NativeType GetStatic<type>Field(JNIEnv *env, jclass clazz,jfieldID fieldID);
| 表 3-7  | GetStatic<type>Field Family of Accessor Routines | 
| GetStatic<type>Field Routine Name | Native Type | 
| 
 | jobject | 
| 
 | jboolean | 
| 
 | jbyte | 
| 
 | jchar | 
| 
 | jshort | 
| 
 | jint | 
| 
 | jlong | 
| 
 | jfloat | 
| 
 | jdouble | 
 
獲取java對(duì)象靜態(tài)屬性的值
 
SetStatic<type>Field Routines
void SetStatic<type>Field(JNIEnv *env, jclass clazz,jfieldID fieldID, NativeType value);
 
| 表 3-8  | SetStatic<type>Field Family of Accessor Routines | 
| SetStatic<type>Field Routine Name | Native Type | 
| 
 | jobject | 
| 
 | jboolean | 
| 
 | jbyte | 
| 
 | jchar | 
| 
 | jshort | 
| 
 | jint | 
| 
 | jlong | 
| 
 | jfloat | 
| 
 | jdouble | 
設(shè)置java對(duì)象靜態(tài)屬性的值
 
 
jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
 
GetStaticMethodID得到j(luò)ava類中static方法 ID,jmethodID為CallStatic<type>Method 函數(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 clazz,jmethodID methodID, va_list args);
 
 
| 表 3-9  | 
| CallStatic <type>Method Routine Name | Native Type | 
| CallStaticVoidMethod() CallStaticVoidMethodA() CallStaticVoidMethodV() | void   | 
| CallStaticObjectMethod() CallStaticObjectMethodA() CallStaticObjectMethodV() | jobject   | 
| CallStaticBooleanMethod() CallStaticBooleanMethodA CallStaticBooleanMethodV | jboolean   | 
| CallStaticByteMethod() CallStaticByteMethodA() CallStaticByteMethodV() | jbyte   | 
| CallStaticCharMethod() CallStaticCharMethodA() CallStaticCharMethodV() | jchar   | 
| CallStaticShortMethod() CallStaticShortMethodA() CallStaticShortMethodV()   | jshort   | 
| CallStaticIntMethod() CallStaticIntMethodA() CallStaticIntMethodV() | jint   | 
| CallStaticLongMethod() CallStaticLongMethodA() CallStaticLongMethodV() | jlong   | 
| CallStaticFloatMethod() CallStaticFloatMethodA() CallStaticFloatMethodV() | jfloat   | 
| CallStaticDoubleMethod() CallStaticDoubleMethodA() CallStaticDoubleMethodV() | jdouble   | 
 
jstring NewString(JNIEnv *env, const jchar *unicodeChars,jsize len);
Array Operations
Registering Native Methods
jint RegisterNatives(JNIEnv *env, jclass clazz,const JNINativeMethod *methods, jint nMethods);
 
typedef struct {
 
 
 
 
 
 
 
} JNINativeMethod
 
Monitor Operations
jint MonitorEnter(JNIEnv *env, jobject obj);
jint MonitorExit(JNIEnv *env, jobject obj);
 
NIO Support
The NIO-related entry points allow native code to access java.nio direct buffers. The contents of a direct buffer can, potentially, reside in native memory outside of the ordinary garbage-collected heap. For information about direct buffers, please see New I/O APIs and the specification of the java.nio.ByteBuffer class.
Three new functions introduced in JDK/JRE 1.4 allow JNI code to create, examine, and manipulate direct buffers:
NewDirectByteBufferGetDirectBufferAddressGetDirectBufferCapacityReflection Support
 
jint GetJavaVM(JNIEnv *env, JavaVM **vm);
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注