1. 程式人生 > >JNI獲取並修改Java中類的變數和靜態變數的值

JNI獲取並修改Java中類的變數和靜態變數的值

對於JNI的基本使用請移步:Hello JNI

本文主要介紹以下幾個函式的使用:

GetObjectClass

GetFieldID,GetStaticFieldID

Get< Type>Field,GetStatic< Type>Field

Set< Type>Field,SetStatic< Type>Field

案例介紹:通過JNI獲取並修改Java中類的變數值

本文也是基於上面的程式碼繼續新增:

JniDemo中新增name,age變數,和accessField(),accessStaticField()方法。

public class JniDemo {
    //路徑:/JNIDemo/app/build/intermediates/classes/debug/com/test/git/jnidemo/JniUtil/JniDemo.class

    public String name = "Lucy";

    public static int age = 10;

    public native String helloJni();

    //修改欄位值
    public native void accessField();
    //修改欄位值(靜態方法)
    public native void
accessStaticField(); static { System.loadLibrary("NdkJniDemo"); } }

生成相應的標頭檔案:

JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessField
  (JNIEnv *, jobject);

JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessStaticField
  (JNIEnv *, jobject);

JniDemo.cpp

通過JNI獲取並修改Java中變數值

對於變數的簽名可以參考:JNI型別

JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessField
        (JNIEnv *env, jobject obj){
    //1.獲取jclass obj是JniDemo物件, JNIDemo.class
    jclass cls = (*env).GetObjectClass(obj);

    //2.獲取jfieldID
    //name:屬性名稱,sig:屬性簽名
    //jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)
    jfieldID fid = (*env).GetFieldID(cls, "name", "Ljava/lang/String;");

    //3.修改name的值

    //a.獲取name屬性的值 Get<Type>Field
    jstring jstr = (jstring) (*env).GetObjectField(obj, fid);

    //b.jstring轉成c字串
    //isCopy:true複製, false不復制,或者NULL
    //const char* GetStringUTFChars(jstring string, jboolean* isCopy)
    const char* c_str = (*env).GetStringUTFChars(jstr, JNI_FALSE);

    //c.拼接得到新的字串
    char new_char[40] = "changed ";
    //複製c_str 到 new_char
    strcat(new_char, c_str);

    //d.c字串轉換成String
    jstring new_jstr = (*env).NewStringUTF(new_char);

    //e.修改name值
    //Set<Type>Field
    (*env).SetObjectField(obj, fid, new_jstr);

    //釋放資源
    (*env).ReleaseStringUTFChars(jstr, c_str);
};
通過JNI獲取並修改Java中靜態變數值
JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessStaticField
        (JNIEnv *env, jobject obj){
    //1.獲取jclass
    jclass cls = env->GetObjectClass(obj);
    //2.獲取age的jfieldID 注意用GetStaticFieldID方法
    jfieldID jfid = env->GetStaticFieldID(cls, "age", "I");
    //3.通過jfid獲取age的屬性值,注意用GetStaticIntField
    jint jage = env->GetStaticIntField(cls, jfid);
    jage ++;
    //4.修改age的屬性值,注意用GetStaticIntField
    env->SetStaticIntField(cls,jfid, jage);
};

MainActivity呼叫

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity-";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        JniDemo jd = new JniDemo();
        Log.i(TAG, "helloJni->" + jd.helloJni());

        Log.i(TAG, "name修改前: " + jd.name);
        jd.accessField();
        Log.i(TAG, "name修改後: " + jd.name);

        Log.i(TAG, "age修改前: " + jd.age);
        jd.accessStaticField();
        Log.i(TAG, "age修改後: " + jd.age);

    }
}

執行結果:

09-24 12:32:44.021 19457-19457/com.test.git.jnidemo I/MainActivity-: helloJni->hello jni
09-24 12:32:44.021 19457-19457/com.test.git.jnidemo I/MainActivity-: name修改前: Lucy
09-24 12:32:44.021 19457-19457/com.test.git.jnidemo I/MainActivity-: name修改後: changed Lucy
09-24 12:32:44.021 19457-19457/com.test.git.jnidemo I/MainActivity-: age修改前: 11
09-24 12:32:44.021 19457-19457/com.test.git.jnidemo I/MainActivity-: age修改後: 12

擴充套件

JNI獲取並修改Java中Array的值

JniDemo.class

public String[] courses = {"語文", "數學"};
public native void accessArrayField();

com_test_git_jnidemo_JniUtil_JniDemo.h標頭檔案

JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessArrayField
  (JNIEnv *, jobject);

JniDemo.cpp

JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_accessArrayField
        (JNIEnv *env, jobject jobj){
    jclass cls = env->GetObjectClass(jobj);
    jfieldID fid = env->GetFieldID(cls, "courses", "[Ljava/lang/String;");
    jobjectArray jarray = (jobjectArray) env->GetObjectField(jobj, fid);
    env->SetObjectArrayElement(jarray, 0, env->NewStringUTF("英語"));
};

MainActivity.java

        Log.i(TAG, "courses修改前: " + jd.courses[0]);
        jd.accessArrayField();
        Log.i(TAG, "courses修改後: " + jd.courses[0]);

列印結果:

09-24 14:36:23.041 18001-18001/com.test.git.jnidemo I/MainActivity-: courses修改前: 語文
09-24 14:36:23.042 18001-18001/com.test.git.jnidemo I/MainActivity-: courses修改後: 英語