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