Javaのネイティブメソッドインターフェース(JNI)をC/C++で実装 (5) jstringクラスやjobjectクラスなどのオブジェクトデータのメソッド

JNI プログラミング (C/C++)

セクション 1: クイック スタート

プロセスをすばやく実行するための簡単なデモ詳細については、「C/C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (1) クイック スタート」を参照してください。

セクション 2: 詳細な例 (C 言語版)

このセクションでは、セクション 1 の内部例の詳細な説明 (C) を提供します。詳細については、「C/C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (2) 例の詳細な説明 (C 言語版)」を参照してください。

セクション 3: 例の詳細な説明 (C++ 言語版)

このセクションでは、セクション 1 (C++) の内部例の詳細な説明に焦点を当てます. 詳細については、「C/C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (3) 詳細な例 (C++ 言語版)」を参照してください。

セクション 4: JNI データ型

このセクションでは、JNI で定義されているいくつかのデータ型を紹介します. 詳細については、「C/C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (4) JNI データ型」を参照してください。

セクション 5: jstring クラスや jobject クラスなどのオブジェクト データのメソッド

このセクションでは、JNI で最も一般的に使用される jstring (java.lang.String) と jobject (Obejct) の操作方法について詳細に説明します。

jstring 型関連のメソッド

// 普通字符串方法
jstring (JNICALL *NewString) (JNIEnv *env, const jchar *unicode, jsize len);
jsize (JNICALL *GetStringLength) (JNIEnv *env, jstring str);
const jchar *(JNICALL *GetStringChars) (JNIEnv *env, jstring str, jboolean *isCopy);
void (JNICALL *ReleaseStringChars) (JNIEnv *env, jstring str, const jchar *chars);
// UTF字符串方法,一般选用这种
jstring (JNICALL *NewStringUTF) (JNIEnv *env, const char *utf);
jsize (JNICALL *GetStringUTFLength) (JNIEnv *env, jstring str);
const char* (JNICALL *GetStringUTFChars) (JNIEnv *env, jstring str, jboolean *isCopy);
void (JNICALL *ReleaseStringUTFChars) (JNIEnv *env, jstring str, const char* chars);

以下では、主に UTF 文字列に関連するメソッドについて説明します。

  • NewStringUTF C の環境と char* 文字列を入力し、JVM で java.lang.String オブジェクトを作成します。成功した場合は jstring オブジェクト参照を返し、それ以外の場合は NULL を返します
  • GetStringUTFLength 入力環境と jstring オブジェクト参照、この java.lang.String の長さを取得
  • GetStringUTFChars 入力環境と jstring オブジェクト参照、それを C char* 文字列に変換します。isCopy パラメーターは、コピー値を返すかどうかを表します (isCopy が true の場合、JVM 内部ソース文字列のコピーを返すことを意味し、新しく生成された文字列に対してisCopy が false の場合、JVM 内のソース文字列へのポインターが返され、新しい文字列オブジェクトは生成されず、変更は元の文字列に対して直接行われますが、これはお勧めできません。 Javaメカニズムの文字列プールでは変更できません;さらに、JNIにはjbooleanを初期化するためのJNI_TRUEとJNI_FALSEがあり、isCopyはjboolean参照を渡すことができます)
  • ReleaseStringUTFChars は、入力パラメーター内の文字列のメモリが使用されなくなったことを JVM に通知し、パラメーターは GetStringUTFChars メソッドを呼び出した入力 char* および出力 jstring に対応します。

各 GetStringUTFChars には、メモリ回復のために対応する ReleaseStringUTFChars が必要であることに注意してください。

注 2、上記の列挙は C の呼び出しメソッドを示しており、C++ の同名のメソッドには最初の env パラメータがありません (オブジェクト メソッドから直接呼び出されるため)。はすべて C メソッドですが、コード例で使用される最後の C++ 実装です。

Jobject 型関連メソッド

クラスの検索

クラスの名前を入力し、クラスに対応する jclass ポインタを返します。Java のクラス名の「.」を「/」に置き換えます。

jclass (JNICALL *FindClass) (JNIEnv *env, const char *name);
// example: 
// jclass array_list_class = env->FindClass("java/lang/Math");

GetObjectClass

jobject を入力し、そのタイプを取得します

jclass (JNICALL *GetObjectClass) (JNIEnv *env, jobject obj);
// example:
// jclass input_class = env->GetObjectClass(input_obj);

Get{/Static}FieldID

オブジェクト フィールドの ID 番号を取得する/クラスの静的フィールドを取得します。この ID 番号は、以降の Get/Set フィールド操作に使用されます。

jfieldID (JNICALL *GetFieldID) 
(JNIEnv *env, jclass clazz, const char *name, const char *sig);
// example:
// jfieldID amount_field = env->GetFieldID(input_class, "amount", "I"); 

jfieldID (JNICALL *GetStaticFieldID)
(JNIEnv *env, jclass clazz, const char *name, const char *sig);
// example:
// jfieldID static_str_field = env->GetStaticFieldID(input_class, "staticString", "Ljava/lang/String;"); 

入力パラメータには、クラスjclass、変数名だけでなく、型シグネチャも含まれることに注意してください.この型シグネチャは、変数の型を記述するために使用されます.型シグネチャの比較表は次のとおりです:

フィールドタイプ サイン
ブール値 Z
バイト B
チャー
ショット S
整数
長さ J
浮く
ダブル D
空所
物体 文字 L の後には、"/" と文字 ";" で区切られた完全なクラス名が続きます (例: "Ljava/lang/String;")。
配列 文字 [ の後に、"[I"、"[Ljava/lang/String;" などの他のタイプの署名が続きます。

Get{/Static}{FIELDTYPE}フィールド

// {FIELDTYPE}代表字段数据类型

// Get{FIELDTYPE}Field系列的函数输入都是jobect和fieldID(使用GetFieldID函数得到的字段ID)
// 返回该对象的对应字段值

jobject GetObjectField(jobject obj, jfieldID fieldID);
jboolean GetBooleanField(jobject obj, jfieldID fieldID);
jbyte GetByteField(jobject obj, jfieldID fieldID);
jchar GetCharField(jobject obj, jfieldID fieldID);
jshort GetShortField(jobject obj, jfieldID fieldID);
jint GetIntField(jobject obj, jfieldID fieldID);
jlong GetLongField(jobject obj, jfieldID fieldID);
jfloat GetFloatField(jobject obj, jfieldID fieldID);
jdouble GetDoubleField(jobject obj, jfieldID fieldID);

// GetStatic{FIELDTYPE}Field系列的函数输入都是jclass和fieldID(使用GetStaticFieldID函数得到的字段ID)
// 由于是获取的类的静态字段,所以输入是jclass而不是jobject
// 返回该类的静态字段值

jobject GetStaticObjectField(jclass clazz, jfieldID fieldID);
jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID);
jbyte GetStaticByteField(jclass clazz, jfieldID fieldID);
jchar GetStaticCharField(jclass clazz, jfieldID fieldID);
jshort GetStaticShortField(jclass clazz, jfieldID fieldID);
jint GetStaticIntField(jclass clazz, jfieldID fieldID);
jlong GetStaticLongField(jclass clazz, jfieldID fieldID);
jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID);
jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID);

Set{/Static}{FIELDTYPE}フィールド

// Set{FIELDTYPE}Field系列的函数输入都是jobect、fieldID(使用GetFieldID函数得到的字段ID)和赋予的新值
    void (JNICALL *SetObjectField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val);
    void (JNICALL *SetBooleanField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val);
    void (JNICALL *SetByteField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val);
    void (JNICALL *SetCharField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val);
    void (JNICALL *SetShortField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val);
    void (JNICALL *SetIntField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jint val);
    void (JNICALL *SetLongField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val);
    void (JNICALL *SetFloatField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val);
    void (JNICALL *SetDoubleField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val);

// SetStatic{FIELDTYPE}Field系列的函数输入都是jclass、fieldID(使用GetStaticFieldID函数得到的字段ID)和赋予的新值
// 由于是set的是类的静态字段,所以输入是jclass而不是jobject
    void (JNICALL *SetStaticObjectField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value);
    void (JNICALL *SetStaticBooleanField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value);
    void (JNICALL *SetStaticByteField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value);
    void (JNICALL *SetStaticCharField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value);
    void (JNICALL *SetStaticShortField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value);
    void (JNICALL *SetStaticIntField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value);
    void (JNICALL *SetStaticLongField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value);
    void (JNICALL *SetStaticFloatField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value);
    void (JNICALL *SetStaticDoubleField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value);

Get{/Static} メソッド ID

後続の Call 操作で使用されるオブジェクト メソッド/クラスの静的メソッドの ID 番号を取得します。

jmethodID GetMethodID(jclass clazz, const char *name, const char *sig);
// example:
// jmethodID object_method = env->GetMethodID(input_class, "someMethod", "(Ljava/lang/String;IZD)V")

jmethodID GetStaticMethodID(jclass clazz, const char *name, const char *sig);
// example:
// jmethodID static_class_method = env->GetMethodID(input_class, "someStaticMethod", "(IFJ)V")

入力パラメータは、jclass、メソッド名、およびメソッド シグネチャです。メソッドのシグネチャには、その入力と出力のデータ型が含まれます。

方法签名格式:"(输入类型签名列表)输出类型签名"

// examples:

"()V"
// 代表是一个无参、返回为void的函数

"(ZSIJ)F"
// 代表输入参数有四个,类型依次为(boolean, short, int, long),输出参数类型为float


"(Ljava/util/ArrayList;II)Ljava/lang/String;"
// 代表输入参数有三个,类型依次为(ArraList, int, int),输出参数类型为String
// 注意L+包名后的分号";"一定要带上

一般メンバ メソッド名はリテラル メソッド名であり、初期化関数は次のように固定されています。"<init>"

Call{/Static}{RETTYPE}メソッド{/V/A}

// {RETTYPE}部分和之前的{FIELDTYPE}同样地,可以使用数据类型进行替换,此处的{RETTYPE}类型代表函数的返回类型
// {/V/A}代表函数的输入参数类型,不写代表直接正常传入"..."可变参数,V代表va_list,A代表const jvalue *

// 此处以{RETTYPE}=Object为例,列举Call{/Static}Void{/V/A}的6个方法
jobject (JNICALL *CallObjectMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...);
jobject (JNICALL *CallObjectMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
jobject (JNICALL *CallObjectMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
jobject (JNICALL *CallStaticObjectMethod) (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
jobject (JNICALL *CallStaticObjectMethodV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
jobject (JNICALL *CallStaticObjectMethodA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);

セクション 6: さまざまな JNI データ型のコード例

このセクションでは、前のセクション 1 ~ 5 を組み合わせて、複数のデータ型を含むサンプル JNI-C++ コードを記述します. 詳細については、「C/C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (6) 複数の JNI データ型コードの例」を参照してください

付録: コード

プロジェクト全体のリソース パッケージ リンク: JNI_C/C++_Demo

おすすめ

転載: blog.csdn.net/O_1CxH/article/details/125587999