1. 程式人生 > >JNI學習筆記:JNIEnv、jobject與jclass詳解

JNI學習筆記:JNIEnv、jobject與jclass詳解

1 前言

  在進行JNI程式設計開發的時候,使用javah生成Native方法對應的Native函式宣告,會發現所有的Native函式的第一個引數永遠是JNIEnv指標,而第二個引數永遠是jobject或jclass中的一個。JNIEnv指標指代何物?具有何種功能?jobject和jclass又有何區別?
本文簡單介紹了JNI程式設計中JNIEnvjobjectjclass這三種基本型別。

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中的類和物件,jobjectjclass 分別指代了其所指代的類和物件,進而訪問成員方法和成員變數等。但其實,我們一般使用javah指令直接生成Native函式的函式原型,故而不必糾結該使用哪種型別。