三、Jni開發(fā):C語(yǔ)言訪問(wèn)JAVA的屬性和方法

這篇文章主要寫了本地方法訪問(wèn)JAVA的屬性、靜態(tài)屬性、方法、靜態(tài)方法。
還有一些相關(guān)的小知識(shí)點(diǎn)在補(bǔ)充中有介紹。

Java代碼

public class JniTest {

public static String static_key = "static key";

public String key = "key";

public static int static_num = 110;

public int num = 110;

public native static String getStringFromC();

public native String getString2FromC(int i);



public native void accessField();

public native void accessStaticField();

public native void accessMethod();

public native void accessStaticMethod();


public static void main(String[] args) {
    System.out.println("\n\n---getStringFromC-----------------------");
    String text1 = getStringFromC();
    System.out.println(text1);
    System.out.println("\n\n----getString2FromC----------------------");
    JniTest j = new JniTest();
    String text2 = j.getString2FromC(5);
    System.out.println(text2);
    System.out.println("\n\n---accessField------------------------");
    j.accessField();
    System.out.println("修改過(guò)后的變量為" + j.key);
    System.out.println("\n\n----accessStaticField-----------------------");
    j.accessStaticField();
    System.out.println("修改過(guò)后的靜態(tài)變量為" + static_num);
    
    System.out.println("\n\n----accessMethod-----------------------");
    j.accessMethod();
    
    System.out.println("\n\n----accessStaticMethod-----------------------");
    j.accessStaticMethod();

}

static{
    System.loadLibrary("JniTest1");
}

//產(chǎn)生指定范圍的隨機(jī)數(shù)
public int genRandomInt(int max){
    System.out.println("genRandomInt 執(zhí)行了...");
    return new Random().nextInt(max); 
}

//產(chǎn)生UUID字符串
public static String getUUID(){
    return UUID.randomUUID().toString();
}
}

C語(yǔ)言代碼

    #define _CRT_SECURE_NO_WARNINGS
    #include "JniTest.h"
    #include <stdio.h>
    #include<stdlib.h>
    #include<string.h>

    JNIEXPORT jstring JNICALL Java_JniTest_getStringFromC
    (JNIEnv * env, jclass jcla) {
        return (*env)->NewStringUTF(env,"String From C");
    }
            
    JNIEXPORT jstring JNICALL Java_JniTest_getString2FromC
    (JNIEnv *env, jobject jobj, jint num) {
                    //此處并沒(méi)有使用num,讀者可以自己實(shí)驗(yàn)
        return (*env)->NewStringUTF(env, "String From C2");;
    }


    JNIEXPORT void JNICALL Java_JniTest_accessField
    (JNIEnv *env, jobject jobj) {

        jclass jcla = (*env)->GetObjectClass(env, jobj);

        jfieldID fid = (*env)->GetFieldID(env, jcla, "key", "Ljava/lang/String;");

        jstring jstr = (*env)->GetObjectField(env, jobj, fid);

        //修改局部變量


        char *c_str = (*env)->GetStringUTFChars(env, jstr, NULL);

        char text[20] = "super";

        strcat(text, c_str);

        jstring new_str = (*env)->NewStringUTF(env, text);
 
        (*env)->SetObjectField(env, jobj, fid, new_str);

    }


    JNIEXPORT void JNICALL Java_JniTest_accessStaticField
    (JNIEnv *env, jobject jobj) {
        jclass jcla = (*env)->GetObjectClass(env, jobj);
        jfieldID fid = (*env)->GetStaticFieldID(env, jcla, "static_num", "I");
        jint num = (*env)->GetStaticIntField(env, jcla, fid);
        num = 119;
        (*env)->SetStaticIntField(env, jcla, fid, num);
    }


    JNIEXPORT void JNICALL Java_JniTest_accessMethod
    (JNIEnv *env, jobject jobj) {
        jclass jcla = (*env)->GetObjectClass(env,jobj);
        jmethodID mid = (*env)->GetMethodID(env, jcla, "genRandomInt", "(I)I");
        jint random = (*env)->CallIntMethod(env, jobj, mid, 200);
        printf("random num:%ld", random);
    }



    JNIEXPORT void JNICALL Java_JniTest_accessStaticMethod
    (JNIEnv *env, jobject jobj) {
        jclass jcla = (*env)->GetObjectClass(env, jobj);

        jmethodID mid = (*env)->GetStaticMethodID(env, jcla, "getUUID", "()Ljava/lang/String;");

        jstring uuid = (*env)->CallStaticObjectMethod(env, jcla, mid);

        char *uuid_str = (*env)->GetStringUTFChars(env, uuid, JNI_FALSE);
        //拼接
        char filename[100];
        sprintf(filename, "D://%s.txt", uuid_str);
        FILE *fp = fopen(filename, "w");
        fputs("i love jason", fp);
        fclose(fp);

    }

以上代碼分別為:

  1. JAVA方法調(diào)用無(wú)參本地方法。
  2. JAVA方法調(diào)用有參的本地方法。
  3. 本地方法訪問(wèn)并修改JAVA中的屬性
  4. 本地方法訪問(wèn)并修改JAVA中的靜態(tài)屬性
  5. 本地方法調(diào)用JAVA中的方法
  6. 本地方法調(diào)用JAVA中的靜態(tài)方法

讀者手?jǐn)]一遍代碼應(yīng)該就能理解。

調(diào)用結(jié)果
生成的UUID文件

這個(gè)地方有個(gè)問(wèn)題:就是random num:60這里為什么會(huì)比accessStaticMethod后打印。還需要研究一下。

補(bǔ)充

  1. 當(dāng)你在JAVA中聲明本地方法時(shí),聲明的是靜態(tài)方法則本地方法屬于類,傳入的是jclass,當(dāng)聲明的是普通方法時(shí),本地方法屬于該類的實(shí)例化對(duì)象,傳入的是jobject。

  2. 在獲取JAVA屬性的時(shí)候需要傳入屬性名稱的字符串,還需要傳入屬性的簽名,如下圖中的 "Ljava/lang/String;" 就是簽名。注意分號(hào)

     jfieldID fid = (*env)->GetFieldID(env, jcla, "key", "Ljava/lang/String;");
    

簽名

當(dāng)本地方法訪問(wèn)JAVA的屬性時(shí),需要寫簽名,基本類型寫的就是 “Z”,“B”這種,如果屬性是一個(gè)對(duì)象,則需要寫L+全類名;例如“Ljava/lang/String;”。
當(dāng)本地方法訪問(wèn)的是JAVA的方法時(shí),如訪問(wèn)上文中public int genRandomInt(int max);這個(gè)方法的簽名就是"(I)I";
訪問(wèn) public static String getUUID();這個(gè)方法時(shí),簽名是"()Ljava/lang/String;"
即先寫括號(hào),括號(hào)內(nèi)寫參數(shù)的前面,括號(hào)后面跟著寫返回值的簽名。
不會(huì)寫的也可以偷懶直接生成。
Jni開發(fā)補(bǔ)充:怎么獲取簽名

  1. 這個(gè)函數(shù)這里的NULL;

     char *c_str = (*env)->GetStringUTFChars(env, jstr, NULL);
    

在VS中按F12打開函數(shù)的原型。

    const char* (JNICALL *GetStringUTFChars)(JNIEnv *env, jstring str, jboolean *isCopy);

注意看,這里的isCopy是一個(gè)布爾類型的指針。此處的iscopy是一個(gè)傳出參數(shù),不是傳入?yún)?shù),目的是讓程序員知道該字符串是否復(fù)制了,至于是否復(fù)制是由Jni自己決定的。

  1. 在尋找某個(gè)屬性或者方法的時(shí)候如果尋找不到,會(huì)拋出一個(gè)“異常"(錯(cuò)誤)。
    這個(gè)地方拋出的其實(shí)是一個(gè)Throwable,所以在JAVA中catch的時(shí)候要catch Throwable。關(guān)于異常這塊這里只做簡(jiǎn)單的了解,后面會(huì)有單獨(dú)的章節(jié)做介紹。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容