利用JNIEnv自變量,程序員可訪問一系列函數。這些函數可劃分為下述類別:
■獲取版本信息
■進行類和對象操作
■控制對java對象的全局和局部引用
■訪問實例字段和靜態字段
■調用實例方法和靜態方法
■執行字串和數組操作
■產生和控制Java異常
獲取版本信息
jint GetVersion(JNIEnv *env);
獲取JNI函數版本信息,
返回值為jint類型,在c/c++中jint為32位數,其中高16位是主版本號,低16位是從版本號
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 環境變量中搜索目錄和zip 文件中具有指定名稱的類。
參數:
name: a fully-qualified class name /”隔開
SINCE JDK/JRE 1.2:
產生和控制Java異常
jint Throw(JNIEnv *env, jthrowable obj);
拋出異常
參數:jthrowable java.lang.Throwable 包中對象.
jint ThrowNew(JNIEnv *env, jclass clazz,const char *message);
通過消息構造一個異常類,其中參數clazz 為 java.lang.Throwable包中的子類
jthrowable ExceptionOccurred(JNIEnv *env);
測試JVM是否有異常發生
SINCE JDK/JRE 1.2:
local reference 和 global reference。
Java 和JNI代碼之間函數調用時,簡單類型,也就是內置類型,比如 int, char 等是值傳遞(pass by value),而其它 Java 對象都是引用傳遞(pass by reference),這些對象引用由 JVM 傳給JNI代碼,每個都有其生命周期。
JNI 函數參數中 jobject 或者它的子類,其參數都是 local reference。Local reference 只在這個 JNI函數中有效,JNI函數返回后,引用的對象就被釋放,它的生命周期就結束了。若要留著日后使用,則需根據這個 local reference 創建 global reference。Global reference 不會被系統自動釋放,它僅當被程序明確調用 DeleteGlobalReference 時才被回收。(JNI多線程機制)
jobject NewGlobalRef(JNIEnv *env, jobject obj);
創建一個新的全局的引用,只能使用DeleteGlobalRef()函數銷毀這個全局引用
參數:
Obj 一個本地引用或者全局引用
void DeleteGlobalRef(JNIEnv *env, jobject globalRef);
銷毀全局引用
參數:
globalRef 使用NewGlobalRef()函數生成的全局引用
銷毀本地的引用
注意:
JDK/JRE 1.1 提供了上面的 DeleteLocalRef 函數,使程序員可以手動刪除本地引用。例如,如果本機代碼遍歷可能很大的對象或數組,并使用每個迭代中的一個元素,好的做法是下一次迭代中創建一個新的本地引用之前刪除本地元素的引用。
JDK/JRE 1.2 和更高版本為本地引用生存周期管理提供了一套額外的函數。他們是下面列出的四種函數。
jint EnsureLocalCapacity(JNIEnv *env, jint capacity);
通知JVM 您將使用超過 16 個本地引用。這將允許 JVM 優化對該本機代碼的本地引用的處理
jint PushLocalFrame(JNIEnv *env, jint capacity);
jobject PopLocalFrame(JNIEnv *env, jobject result);
先調用PushLocalFrame,然后創建局部引用,并對其進行處理,最后調用PushLocalFrame釋放局部引用,這時Java虛擬機也可以對其指 向的對象進行垃圾回收??梢杂肅語言的棧來理解這對JNI API,調用PushLocalFrame之后Native代碼創建的所有局部引用全部入棧,當調用PopLocalFrame之后,入棧的局部引用除了 需要返回的局部引用(PushLocalFrame和PopLocalFrame這對函數可以返回一個局部引用給外部)之外,全部出棧,Java虛擬機這 時可以釋放他們指向的對象。具體的用法可以參考手冊。這兩個函數使JNI的局部引用由于和C語言的局部變量用法類似,所以強烈推薦使用
jobject NewLocalRef(JNIEnv *env, jobject ref);
1、Java虛擬機默認為Native引用分配的局部引用數量是有限的,大部分的Java虛擬機實現默認分配16個局部引用。當然Java虛擬 機也提供API(PushLocalFrame,EnsureLocalCapacity)讓你申請更多的局部引用數量(Java虛擬機不保證你一定能申 請到)。有限的資源當然要省著點用,否則將會被Java虛擬機無情拋棄(程序崩潰)。JNI編程中,實現Native代碼時強烈建議調用PushLocalFrame,EnsureLocalCapacity來確保Java虛擬機為你準備好了局部變量空間。
2、如果你實現的Native函數是工具函數,會被頻繁的調用。如果你在Native函數中沒有顯示刪除局部引用,那么每次調用該函數Java虛擬機都會創建一個新的局部引用,造成局部引用過多。尤其是該函數在Native代碼中被頻繁調用,代碼的控制權沒有交還給Java虛擬機,所以Java虛擬機根本沒有機會釋放這些局部變量。退一步講,就算該函數直接返回給Java虛擬機,也不能保證沒有問題,我們不能假設Native函數返回Java虛 擬機之后,Java虛擬機馬上就會回收Native函數中創建的局部引用,依賴于Java虛擬機實現。所以我們在實現Native函數時一定要記著刪除不 必要的局部引用,否則你的程序就有潛在的風險,不知道什么時候就會爆發。
3、如果你Native函數根本就不返回。比如消息循環函數——死循環等待消息,處理消息。如果你不顯示刪除局部引用,很快將會造成Java虛擬機的局部引用內存溢出。
Weak Global References
全局的弱引用是一種特殊的全局引用,與普通的全局引用不同全局的弱引用允許Java 對象進行垃圾回收,當垃圾收集器運行時,它將釋放對象,如果引用的對象只使用弱引用
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);
分配一個新的 Java 對象,而不調用任何對象的構造函數,僅僅是內存創建
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.
分配一個新的java對象,調用指定的構造函數,構造函數使用methodID指定
jclass GetObjectClass(JNIEnv *env, jobject obj);
根據類的引用返回類的類型
jboolean IsInstanceOf(JNIEnv *env, jobject obj,jclass clazz);
測試類的引用類型,是返回JNI_TRUE 否則 返回JNI_FALSE
jboolean IsSameObject(JNIEnv *env, jobject ref1,jobject ref2);
測試兩個引用類型是否指向同一個空間,是返回JNI_TRUE 否則 返回JNI_FALSE
accessing Fields of Objects
jfieldID GetFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
GetFieldID是得到java類中的參數ID,只能調用類中聲明為 public的屬性,jfieldID為 Get<type>Field andSet<type>Field 函數族使用
參數:
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對象屬性的值
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 |
設置java對象屬性的值
jmethodID GetMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
GetMethodID得到java類中方法的ID,它只能調用類中聲明為 public的方法,jmethodID為Call<type>Method函數族使用
參數:
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 |
調用java方法通過jmethodID指定
如果想要調用一個對象的父類方法,而不是子類的這個方法的話,就可以使用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得到java類中static 屬性ID,jfieldID為GetStatic<type>Field and SetStatic<type>Field函數族使用
參數:
clazz java類對象
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對象靜態屬性的值
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 |
設置java對象靜態屬性的值
jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
GetStaticMethodID得到java類中static方法 ID,jmethodID為CallStatic<type>Method 函數使用
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);
新聞熱點
疑難解答