JNIシリーズ入門のC言語とJavaの双方向通信(一)
6290 ワード
JNIシリーズ文章:JNIシリーズの入門Hello JNI C(一)JNIシリーズの入門Hello JNI C(二)JNIシリーズ入門のC言語とJavaの双方向通信(一)JNIシリーズ入門のC言語とJavaの双方向通信(二)JNIシリーズ入門のC言語中国語文字列乱符号問題
一、概説 Java層C層への通信 静的無パラメータnativeメソッド を呼び出す.非静的無パラメータnativeメソッド を呼び出す. C層Java層への通信 C層Java層の属性 へのアクセスと変更 C層Java層の静的属性 へのアクセスと変更 C層がJava層にアクセスする方法 C層がJava層にアクセスする静的方法 CレイヤはJavaレイヤの構築方法にアクセスし、Javaオブジェクトを作成して を返す. javaにおける受信配列 Cで生成された配列はjava に戻る.
二、実現
Java層からC層への通信静的無パラメータnativeメソッド を呼び出す.
Javaで2つのnativeメソッドを宣言し、javahコマンドでヘッダファイルを生成します.具体的なヘッダファイル生成手順は、JNIシリーズの入門Hello JNI C(一)を参照してください.
具体的な実装:
getStringFromC関数では、(*env)を使用してNewStringUTF関数を呼び出し、C文字ポインタ、すなわち文字列を入力することでjstringタイプの文字列(javaデータ型のStringに対応)を作成するのは簡単です.JNIEnv自体が構造体ポインタであるため、envは構造体2次ポインタ変数であり、NewStringUTF関数はJNIEnvという構造体ポインタの構造体に定義された関数(これは関数ポインタ)であるため、構造体1次ポインタ変数のアドレスを取得するには(*env)を使用する必要があります.に表示されます.具体的には、前の記事JNIシリーズの入門Hello JNI C(二)getNewString関数に1つのパラメータが追加されています.jstr_inputはjavaにおけるnativeメソッドのパラメータString inputを表し、関数実装ではまずjstringをc文字列に変換し、cの関数ライブラリstring.hヘッダファイルを導入し、strcatを使用して新しいc文字列をつなぎ合わせ、NewStringUTF関数で新しいC文字列->jstringをjavaに返します.
出力結果:
Paste_Image.png
これはjavaのnativeメソッド呼び出しで、Cの中国語文字列は文字化けして、javaが入ってきた中国語文字列は文字化けしていないことがわかります.Cの中国語文字列の文字化けし問題について、次の文章で解決策を説明します.非静的無パラメータnativeメソッド を呼び出す.
Cのヘッダファイル実装:
非静的nativeメソッドでは、関数のパラメータがjobjectになります.このjobjはjavaで非静的nativeメソッドを呼び出すオブジェクトです.たとえば、次のようにします.
jobjはオブジェクトjtを表す.静的jclassはnativeメソッドが宣言したクラスタイプ、例えばJniTest.classを表す.
C層からJava層への通信 CレイヤJavaレイヤのプロパティへのアクセスと変更javaでプロパティnameを定義します:
C層を用いてJava層を呼び出すコンテンツの作成を容易にするために、次にJava層にnativeメソッドを作成し、C層native関数実装でJava層にアクセスするコンテンツを呼び出す.
Cの実装:
コードには注釈がはっきり書かれています.ここで注意しなければならないのは、属性と方法に関する署名ルールです.
公式ドキュメント
公式ドキュメント
データ型
に署名
boolean
Z
byte
B
char
C
short
S
int
I
long
J
float
F
double
D
void
V
Object
Lで始まると、パッケージの完全なタイプ名を/区切って、「;」(セミコロン)を付けます.たとえば、String署名はLjava/lang/Stringです.
int[]Object[]
[冒頭で、int[]署名が[I、さらにint[]]署名が[[I、object配列署名が[Ljava/lang/Object; C層Java層の静的属性 へのアクセスと変更
Javaで静的プロパティsizeを定義します.
Cでjavaのこの静的属性を変更するための関数を実装します.
上記の非静的属性へのアクセスにより、静的属性は簡単になります.同じ方法です.jclass->属性を取得するjfieldID->属性値を取得->属性値を設定します.また、属性値を取得するのは一般的にGetStaticFieldで、属性値を設定するのは一般的にSetStaticFieldです.
JNIシリーズ文章:JNIシリーズの入門Hello JNI C(一)JNIシリーズの入門Hello JNI C(二)JNIシリーズ入門のC言語とJavaの双方向通信(一)JNIシリーズ入門のC言語とJavaの双方向通信(二)JNIシリーズ入門のC言語中国語文字列乱符号問題
一、概説
二、実現
Java層からC層への通信
JniTest.java
// native , JNI (JNIEnv *env, jclass jcls)
public native static String getStringFromC();
// JNI (JNIEnv *env, jclass jcls, jstring jstr_input)
public native static String getNewString(String input);
Javaで2つのnativeメソッドを宣言し、javahコマンドでヘッダファイルを生成します.具体的なヘッダファイル生成手順は、JNIシリーズの入門Hello JNI C(一)を参照してください.
com_jerry_jnitest_JniTest.h
JNIEXPORT jstring JNICALL Java_com_jerry_jnitest_JniTest_getStringFromC
(JNIEnv *, jclass);
JNIEXPORT jstring JNICALL Java_com_jerry_jnitest_JniTest_getNewString
(JNIEnv *, jclass, jstring);
具体的な実装:
// , C
JNIEXPORT jstring JNICALL Java_com_jerry_jnitest_JniTest_getStringFromC
(JNIEnv *env, jclass jcls) {
char *text = "Hi, Jerry! , !";
return (*env)->NewStringUTF(env, text);
}
// , C java java
JNIEXPORT jstring JNICALL Java_com_jerry_jnitest_JniTest_getNewString
(JNIEnv *env, jclass jcls, jstring jstr_input) {
// java jstring -> c
char *input = (*env)->GetStringUTFChars(env, jstr_input, NULL);
char text[30] = "Jerry";
//
char *new_text = strcat(text, input);
printf("newText = %s
", new_text);
// jstring java
jstring jstr_new = (*env)->NewStringUTF(env, new_text);
return jstr_new;
}
getStringFromC関数では、(*env)を使用してNewStringUTF関数を呼び出し、C文字ポインタ、すなわち文字列を入力することでjstringタイプの文字列(javaデータ型のStringに対応)を作成するのは簡単です.JNIEnv自体が構造体ポインタであるため、envは構造体2次ポインタ変数であり、NewStringUTF関数はJNIEnvという構造体ポインタの構造体に定義された関数(これは関数ポインタ)であるため、構造体1次ポインタ変数のアドレスを取得するには(*env)を使用する必要があります.に表示されます.具体的には、前の記事JNIシリーズの入門Hello JNI C(二)getNewString関数に1つのパラメータが追加されています.jstr_inputはjavaにおけるnativeメソッドのパラメータString inputを表し、関数実装ではまずjstringをc文字列に変換し、cの関数ライブラリstring.hヘッダファイルを導入し、strcatを使用して新しいc文字列をつなぎ合わせ、NewStringUTF関数で新しいC文字列->jstringをjavaに返します.
public static void main(String[] args) {
// main native
System.out.println(getStringFromC());
System.out.println(getNewString(" ..."));
}
出力結果:
Paste_Image.png
これはjavaのnativeメソッド呼び出しで、Cの中国語文字列は文字化けして、javaが入ってきた中国語文字列は文字化けしていないことがわかります.Cの中国語文字列の文字化けし問題について、次の文章で解決策を説明します.
// native , NI (JNIEnv *env, jobject jobj)
public native String getNameFromC();
Cのヘッダファイル実装:
//
JNIEXPORT jstring JNICALL Java_com_jerry_jnitest_JniTest_getNameFromC
(JNIEnv *env, jobject jobj) {
return (*env)->NewStringUTF(env, "call getNameFromC");
}
非静的nativeメソッドでは、関数のパラメータがjobjectになります.このjobjはjavaで非静的nativeメソッドを呼び出すオブジェクトです.たとえば、次のようにします.
JniTest jt = new JniTest();
jt.getNameFromC();
jobjはオブジェクトjtを表す.静的jclassはnativeメソッドが宣言したクラスタイプ、例えばJniTest.classを表す.
C層からJava層への通信
public String name = "Jerry";
C層を用いてJava層を呼び出すコンテンツの作成を容易にするために、次にJava層にnativeメソッドを作成し、C層native関数実装でJava層にアクセスするコンテンツを呼び出す.
/**
* @return
*/
public native String accessField();
Cの実装:
// 1. java
// java name
JNIEXPORT jstring JNICALL Java_com_jerry_jnitest_JniTest_accessField
(JNIEnv *env, jobject jobj) {
// java name class
jclass jcls = (*env)->GetObjectClass(env, jobj);
// name fieldID
// ( :name Java , )
jfieldID fid = (*env)->GetFieldID(env, jcls, "name", "Ljava/lang/String;");
if (fid == NULL) {
printf("fid is NULL!");
}
// fieldId
jstring jstr_fvalue = (*env)->GetObjectField(env, jobj, fid);
// , jstring -> c
// :JNI_TRUE 1, true ( ),
// JNI_FALSE ( java ), NULL
char *ch_fvalue = (*env)->GetStringUTFChars(env, jstr_fvalue, NULL);
// string.h
char text[20] = "hello ";
char *new_fvalue = strcat(text, ch_fvalue);
// c -> java
jstring new_jstr = (*env)->NewStringUTF(env, new_fvalue);
//
(*env)->SetObjectField(env, jobj, fid, new_jstr);
return new_jstr;
}
コードには注釈がはっきり書かれています.ここで注意しなければならないのは、属性と方法に関する署名ルールです.
公式ドキュメント
公式ドキュメント
データ型
に署名
boolean
Z
byte
B
char
C
short
S
int
I
long
J
float
F
double
D
void
V
Object
Lで始まると、パッケージの完全なタイプ名を/区切って、「;」(セミコロン)を付けます.たとえば、String署名はLjava/lang/Stringです.
int[]Object[]
[冒頭で、int[]署名が[I、さらにint[]]署名が[[I、object配列署名が[Ljava/lang/Object;
Javaで静的プロパティsizeを定義します.
private static int size = 26;
Cでjavaのこの静的属性を変更するための関数を実装します.
// 2. java
// java size
JNIEXPORT void JNICALL Java_com_jerry_jnitest_JniTest_accessStaticField
(JNIEnv *env, jobject jobj) {
// jclass
jclass cls = (*env)->GetObjectClass(env, jobj);
// jfieldID
jfieldID fID = (*env)->GetStaticFieldID(env, cls, "size", "I");
//
jint size= (*env)->GetStaticIntField(env, cls, fID);
size += 12;
//
(*env)->SetStaticIntField(env, cls, fID, size);
}
上記の非静的属性へのアクセスにより、静的属性は簡単になります.同じ方法です.jclass->属性を取得するjfieldID->属性値を取得->属性値を設定します.また、属性値を取得するのは一般的にGetStaticFieldで、属性値を設定するのは一般的にSetStaticFieldです.
JNIシリーズ文章:JNIシリーズの入門Hello JNI C(一)JNIシリーズの入門Hello JNI C(二)JNIシリーズ入門のC言語とJavaの双方向通信(一)JNIシリーズ入門のC言語とJavaの双方向通信(二)JNIシリーズ入門のC言語中国語文字列乱符号問題