JNI學習筆記:JNIEnv、jobject與jclass詳解
阿新 • • 發佈:2019-02-18
1 前言
在進行JNI程式設計開發的時候,使用javah生成Native方法對應的Native函式宣告,會發現所有的Native函式的第一個引數永遠是JNIEnv指標,而第二個引數永遠是jobject或jclass中的一個。JNIEnv指標指代何物?具有何種功能?jobject和jclass又有何區別?
本文簡單介紹了JNI程式設計中JNIEnv
、jobject
和jclass
這三種基本型別。
2 JNIEnv指標
JNIEnv,顧名思義,指代了Java本地介面環境(Java Native Interface Environment),是一個JNI介面指標,指向了本地方法的一個函式表,該函式表中的每一個成員指向了一個JNI函式,本地方法通過JNI函式來訪問JVM中的資料結構,詳情如下圖:
而JNIEnv
指標在<jni.h>
檔案中的具體實現是一個包含諸多JNI函式的結構體,在C語言中該結構體的名字定義為JNIEnv_
。區域性摘要如下:
/*
* We use inlined functions for C++ so that programmers can write:
*
* env->FindClass("java/lang/String")
*
* in C++ rather than:
*
* (*env)->FindClass(env, "java/lang/String")
*
* in C.
*/
struct JNIEnv_ {
const struct JNINativeInterface_ *functions;
#ifdef __cplusplus
jint GetVersion() {
return functions->GetVersion(this);
}
jclass DefineClass(const char *name, jobject loader, const jbyte *buf,
jsize len) {
return functions->DefineClass(this, name, loader, buf, len);
}
...
jclass GetObjectClass(jobject obj) {
return functions->GetObjectClass(this,obj);
}
jboolean IsInstanceOf(jobject obj, jclass clazz) {
return functions->IsInstanceOf(this,obj,clazz);
}
jmethodID GetMethodID(jclass clazz, const char *name,
const char *sig) {
return functions->GetMethodID(this,clazz,name,sig);
}
...
}
深入去看JNIEnv結構體的話,不難發現,這個結構體當中包含了幾乎有所的JNI函式,大致可以分為如下幾類:
函式名 | 備註 |
---|---|
NewObject |
建立Java類中的物件 |
NewString |
建立Java類中的String物件 |
New<Type>Array |
建立型別為Type的陣列物件 |
Get<Type>Field |
獲取型別為Type的欄位 |
Set<Type>Field |
設定型別為Type的欄位的值 |
GetStatic<Type>Field |
獲取型別為Type的static的欄位 |
SetStatic<Type>Field |
設定型別為Type的static的欄位的值 |
Call<Type>Method |
呼叫返回型別為Type的方法 |
CallStatic<Type>Method |
呼叫返回值型別為Type的static方法 |
3 jobject與jclass型別
jobject與jclass通常作為JNI函式的第二個引數,當所宣告Native方法是靜態方法時,對應引數jclass
,因為靜態方法不依賴物件例項,而依賴於類,所以引數中傳遞的是一個jclass
型別。相反,如果宣告的Native方法時非靜態方法時,那麼對應引數是jobject
。
其在`
typedef _jobject *jobject;
typedef _jclass *jclass;
...
class _jobject {};
class _jclass : public _jobject {};
...
為了能夠在Native層訪問Java中的類和物件,jobject
和jclass
分別指代了其所指代的類和物件,進而訪問成員方法和成員變數等。但其實,我們一般使用javah指令直接生成Native函式的函式原型,故而不必糾結該使用哪種型別。