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メソッド
  • を呼び出す.
    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メソッド
  • を呼び出す.
    // 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層への通信
  • CレイヤJavaレイヤのプロパティへのアクセスと変更javaでプロパティnameを定義します:
  • 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;
  • C層Java層の静的属性
  • へのアクセスと変更
    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言語中国語文字列乱符号問題