ローカルメソッド呼び出し3

3124 ワード

ローカル呼び出しに関する知識を続行します.Javaが変数をどのように適合させるか、jni呼び出しのメソッド仕様、およびいくつかのjniメソッド呼び出しの注意点など、javaがどのように呼び出すかについては、前述した知識があります.
    前述したように,呼び出しのプロセスは,本当に使用すれば,パラメータの下向き伝達だけでは絶対に不十分であるため,うまくいかないことが分かった.私たちは下層のコードが上層にアクセスするだけでなく、お互いの方法を繰り返し呼び出す必要があります.そうすればcoolになりますか.そして、さまざまなニーズを柔軟に満たすことができます.仏経が言ったように、入ることができて退くことができて、本当の法器(入ることができて退くことができて、進退することができて、趙雲式の覇気)で、ありますか?
    では、まずインスタンスドメインへのアクセスについて説明しましょう.Javaプログラムでは、次のコードなど、クラス内のグローバル変数を使用する方法がたくさんあります.
class Employee{
    double salary = 0;
    
    public void raiseSalary(double byPercent){
        salary += 1 + byPercent / 100;
    }
}

    よくある方法ですよね?今、私たちはこのraiseSalaryを地元の方法に変えます.前の内容に基づいてjavahは次の方法を生成することができます.
JNIEXPORT void JNICALL Java_Employee_raiseSalary(JNIEnv *, jobject, jdouble)

    この方法を見て、前に話したことと何が違うか見ることができますか.何?入ることができますか?退くことができますか?私は趙雲を代表して、ひざまずいてあげました...ええと、2つの違いがあります.1つ目は、salary変数がEmployeeの変数であり、パラメータを通じてc層に伝達されていません.これは後で重点的に紹介します.もう1つは、2番目の入力パラメータを見てみると、static静的メソッドが使用されているため、伝達されたのはjclassであり、ここでは、伝達されたのは
jobject.これも合理的ですが、静的な方法にはオブジェクトがないからです.
    はい、javaオブジェクトが伝わってきて、後でよく想像しましたよね.ただし、直接アクセスするには、仮想マシンが内部データレイアウトを露出する必要があるため、JNIはプログラマに特殊なJNI関数を呼び出してデータの値を取得し、設定する必要があります.ここではGetdoubleFieldとSetDoubleField関数を使用します.もちろん、他のタイプもあります.一般的な構文は次のとおりです.
x = (*env)->GetXxxField(env, this_obj, fieldID);
(*env)->SetXxxField(env, this_obj, fieldID, x);

    ここで、また2つの疑問が生まれました.1つは
fieldIDは何ですか?また、GetObjectFieldメソッドで返されるオブジェクトは、どのようなclassで定義されますか?
    まずFieldIDを見てみましょう.これは特殊なタイプの値で、fieldIDは構造内のドメインを表します.GetFieldID関数を使用してfieldIDを取得します.

    jfieldID id_salary = (*env)->GetFieldID(env, class_Employee, "salary", "D");

    文字列「D」は、タイプがdoubleであることを示す.これは後で紹介します.
    テクスチャidに似ているような気がしますか?JNIの設計者はデータドメインを直接露出したくないので,データドメイン値を取得して設定する関数を提供しなければならない.これらの関数のオーバーヘッドを最小化するために、ドメイン名計算ドメインID(最もコストの高いステップ)から単一のステップとして分解される.このように、特定のドメインを繰り返し取得して設定すると、ドメイン識別子の計算にかかるコストは1回しかありません.
    2つ目は、どうやってclassを手に入れますか?jniはclassを得る2つの方法があります.
   
jclass class_Employee = (*env)->GetObjectClass(env, this_obj);

    FindClass関数を使用すると、クラス名を文字列で指定できます(パケット分割記号の代わりに/を使用するのは不思議です.)
   
jclass class_String = (*env)->FindClass(env, "java/lang/String");

    反射的に見えますね.(後ろを見れば見るほど、実はjniのjava層のmethod呼び出しも反射の形式で、彼らはそれぞれ反射のfieldとmethodに対応しています)
    では、javaのドメインへのアクセス方法について説明しました.最後に、最初の方法をjni層のコードに完全に変換します.
JNIEXPORT void JNICALL Java_Employee_raiseSalary(JNIEnv* env, jobject this_obj, jdouble byPercent){
    jclass class_Employee = (*env)->GetObjectClass(env, this_obj);
    jfieldID id_salary = (*env)->GetFiledID(env, class_Employee, "salary", "D");
    jdouble salary = (*env)->getDoubleField(env, this_obj, id_salary);
    salary += 1 + byPercent;
    (*env)->SetDoubleField(env, this_obj, id_salary, salary);
}