JNI定義
JNI是Java程序設(shè)計(jì)語言功能最強(qiáng)的特征,它允許Java類的某些方法原生實(shí)現(xiàn),同時(shí)讓它們能夠像普通Java方法一樣被調(diào)用和使用。
方法聲明。
原生方法中必須存在的兩個(gè)參數(shù):JNIEnv*,jobject。第一個(gè)參數(shù)JNIEnv是指向JNI函數(shù)列表的接口指針,第二個(gè)參數(shù)jobject是獲取類引用或?qū)嵗谩?/p>
JNIEnv接口指針
- C代碼中,指向JNINativeInterface結(jié)構(gòu)的指針。
- C++代碼中,是C++類實(shí)例。
實(shí)例方法與靜態(tài)方法
- 實(shí)例方法與類實(shí)例相關(guān),只能在類實(shí)例中調(diào)用。
- 靜態(tài)方法不與實(shí)例相關(guān),可以在靜態(tài)上下文直接調(diào)用。
靜態(tài)方法和實(shí)例方法均可以聲明為原生的,可以通過JNI技術(shù)以源生代碼的形式提供實(shí)現(xiàn)。
數(shù)據(jù)類型
- 基本數(shù)據(jù)類型:布爾型,字節(jié)型,字符型,短整型,整型,長(zhǎng)整型,浮點(diǎn)型和雙精度浮點(diǎn)型。
Java類型 | JNI類型 | C/C++類型 | 大小 |
---|---|---|---|
boolean | jblloean | unsigned char | 無符號(hào)8位 |
bety | jbyte | char | 有符號(hào)8位 |
char | jchar | unsigned short | 無符號(hào)16位 |
short | jshort | short | 有符號(hào)16位 |
int | jnit | int | 有符號(hào)32位 |
long | jlong | long long | 有符號(hào)64位 |
float | jfloat | float | 32位 |
double | jdouble | double | 64位 |
- 引用類型:與基本數(shù)據(jù)類型不同,引用類型對(duì)原生方法是不透明的,內(nèi)部數(shù)據(jù)結(jié)構(gòu)并不直接向原生代碼公開。
Java類型 | 原生類型 |
---|---|
java.lang.Class | jclass |
java.lang.Throwable | jthrowable |
java.lang.String | jstring |
Other objects | jobjects |
java.lang.Object[] | jobjectArray |
boolean[] | jbooleanArray |
byte[] | jbyteArray |
char[] | jcharArray |
short[] | jshortArray |
int[] | jintArray |
long[] | jlongArray |
float[] | jfloatArray |
double[] | jdoubleArray |
Other arrays | jarray |
對(duì)引用數(shù)據(jù)類型的操作
引用類型以不透明的引用方式傳遞給原生代碼,而不是以原生數(shù)據(jù)類型的形式呈現(xiàn),因此引用類型不能直接使用和修改。
-
字符串操作
- 創(chuàng)建字符串
/*用給定的C字符串創(chuàng)建Java字符串*/ jstring javaString; javaString = (*env)->NewString(env,"Hello World!");
/*將Java字符串轉(zhuǎn)換成C字符串*/ const jbyte* str; jboolean isCopy; srt = (*env)->GetStringUTFChars(env,javaString,&isCopy);
- 通過JNI GetStringChars和GetStringUTFChars函數(shù)獲得的C字符串在原生代碼中使用完之后需要正確的釋放,否則會(huì)造成內(nèi)存泄漏。
(*env)->ReleaseStringUTFChars(env,javaString,str);
-
數(shù)組操作
- 創(chuàng)建數(shù)組
/*在原生代碼中創(chuàng)建數(shù)組*/ jintArray javaArray; javaArray = (*env)->NewIntArray(env,10);
- 訪問數(shù)組元素
- 將Java數(shù)組區(qū)復(fù)制到C數(shù)組中
jint nativeArray[10]; (*env)->GetIntArrayRegion(env,javaArray,0,10,nativeArray);
- 從C數(shù)組向Java數(shù)組提交所作的修改
(*env)->SetIntArrayRegion(env,javaArray,0,10,nativeArray);
- 對(duì)直接指針的操作
/*獲得指向Java數(shù)組元素的直接指針*/ jint* nativeDirectArray; jboolean isCopy; nativeDirectArray = (*env)->GetIntArrayElements(env,javaArray,&isCopy);
/*釋放指向Java數(shù)組元素的直接指針*/ (*env)->ReleaseIntArrayElements(env,javaArray,nativeDirectArray,0);
NIO 操作
原生I/O(NIO)在緩沖管理區(qū),大規(guī)模網(wǎng)絡(luò)和文件I/O及字符集支持方面的性能有所改進(jìn)。JNI提供了原生代碼中使用NIO的函數(shù)。
- 創(chuàng)建直接字節(jié)緩沖區(qū)
unsigned char* buffer = (unsigned char*) malloc(1024);
jobject directBuffer;
directBuffer = (*env)->NewDirectByteBuffer(env,buffer,1024);
原生方法中的內(nèi)存分配超出了虛擬機(jī)的管理范圍,且不能用虛擬機(jī)的垃圾回收器回收原生方法中的內(nèi)存。原生方法應(yīng)該通過釋放未使用的內(nèi)存分配以避免內(nèi)存泄漏來正確管理內(nèi)存
- 通過Java字節(jié)緩沖區(qū)獲取原生字節(jié)數(shù)組
unsigned char* buffer;
buffer = (unsigned char*)(*env)->GetDirectBufferAddress(env,directBuffer);
訪問域
- 帶有靜態(tài)域和實(shí)例域的Java類
public class JavaClass {
private String instanceField = "Instance Field";
private static String staticField = "static Field";
}
- 獲取域ID
- 用對(duì)象引用獲得類
jclass clazz; clazz = (*env)->GetObjectClass(env,instance);
- 獲取實(shí)例域的域ID
jfieldID instanceFieldId; staticFieldId = (*env)->GetFieldID(env,clazz,"instanceField","Ljava/lang/String;");
- 獲取靜態(tài)域的域ID
jfieldID staticFieldId; staticFieldId = (*env)->GetStaticFieldID(env,clazz,"staticField","Ljava/lang/String;");
- 獲取域
- 獲取實(shí)例域
jstring instanceFieldStr; instanceField = (*env)->GetObjectField(env,instance,instanceFieldIdStr);
- 獲取靜態(tài)域
jstring staticFieldStr; staticField = (*env)->GetStaticObjectField(env,clazz,staticFieldIdStr);
調(diào)用方法
- 帶有靜態(tài)方法和實(shí)例方法的Java類
public class JavaClass {
private String instanceMethod(){
return "Instance Method";
}
private static String staticMethod(){
return "Static Method";
}
}
-
獲取方法ID
- 獲取實(shí)例方法的方法ID
jmethodID = instanceMethodId; instanceMethodId = (*env)->GetMethodID(env,clazz,"instanceMethod","()Ljava/lang/String;");
- 獲取靜態(tài)方法的方法ID。
jmethodID staticMethodId; staticMethodId = (*env)->GetStaticMethodID(env,clazz,"staticMethod","()Ljava/lang/String;");
調(diào)用方法
- 調(diào)用實(shí)例方法
(*env)->CallStringMethod(env,instance,instanceMethodId);
- 調(diào)用靜態(tài)方法
(*env)->CallStaticStringMethod(env,instance,staticMethodId );
域和方法描述
- 使用java類文件反匯編程序——javap,解壓縮類中的域和方法描述符。
外部工具程序配置