JNI開發(fā)系列④C語言調(diào)用構(gòu)造方法

接續(xù)上篇JNI開發(fā)系列③C語言調(diào)用Java字段與方法

前情提要

Java調(diào)用C方法很簡單 , 只需要編寫native方法即可 , 通過C去調(diào)用Java的字段與方法 , 則需要比較復(fù)雜的操作 , 上篇中介紹了 , C調(diào)用的Java字段與方法的幾個(gè)套路:

步驟一 、 得到j(luò)class, 字節(jié)碼對象 , 如果是static native修飾 , 則函數(shù)會以jclass類型傳入 , 非靜態(tài)則需要得到j(luò)class類型 。

步驟二 、得到字段或方法ID , 區(qū)分靜態(tài)字段與對象字段 , 靜態(tài)字段或方法調(diào)用(env)->GetStaticFieldID,(env)->GetMethodID函數(shù)得到ID , 對象字段調(diào)用(env)->GetFieldID,(env)->GetStaticMethodID得到ID 。 可以得到一個(gè)套路 , 靜態(tài)修飾的 , 則調(diào)用static標(biāo)識的函數(shù) , 非靜態(tài)的則調(diào)用常規(guī)函數(shù) 。

步驟三 、 取得字段的值或調(diào)用方法 , 需要注意的是, 得到字段的值與調(diào)用方法 , 都有類型的區(qū)分 。引用類型則使用GetObjectField, CallStaticObjectMethod, 其他類型 , 則有對于的jxxx類型對應(yīng) 。套路簡寫:Get<Type>Field, GetStatic<Type>Field, Call<Type>Method, CallStatic<Type>Method 。

步驟四 、 類型轉(zhuǎn)換 , 如果是Java引用類型 , 則需要進(jìn)行類型轉(zhuǎn)換

C 調(diào)用Java對象的構(gòu)造方法

C調(diào)用Java的構(gòu)造方法與調(diào)用普通方法略有不同 , 其不同之處在于方法名稱上 , 普通方法直接使用方法名 , 構(gòu)造方法則不是使用類名 , 而使用一個(gè)固定寫法<init> 。

java code  使用C語言創(chuàng)建一個(gè)Date對象,獲取時(shí)間戳

private native long accessConstructorMethod() ;

public static void main(String[] args) {
     long timeLong = jni.accessConstructorMethod() ;
         
     SimpleDateFormat sdf = new SimpleDateFormat();
     sdf.applyPattern("yyyy-MM-dd  HH:mm:ss") ;
     String dateString = sdf.format(new Date(timeLong)) ;
}

使用C創(chuàng)建Java對象 , 并調(diào)用方法

/*訪問java對象的構(gòu)造方法*/
JNIEXPORT jlong JNICALL Java_com_zeno_jni_HelloJni_accessConstructorMethod
(JNIEnv *env, jobject jobj) {

    // 找到Date的jclass
    jclass dateCls = (*env)->FindClass(env, "java/util/Date");

    // 得到構(gòu)造方法id
    jmethodID dateConstructMid = (*env)->GetMethodID(env, dateCls, "<init>", "()V");

    // 創(chuàng)建Date對象
    jobject dateObj = (*env)->NewObject(env, dateCls, dateConstructMid);

    // 得到getTime方法ID
    jmethodID getTimeMid = (*env)->GetMethodID(env, dateCls, "getTime", "()J");

    // 調(diào)用getTime方法
    jlong timeLong = (*env)->CallLongMethod(env, dateObj, getTimeMid);

    printf("new Date().getTime : %lld\n", timeLong);

    return timeLong;
}

Tips:

C實(shí)例化Java對象的時(shí)候 , 首先需要找到對象的class , 以全類名表示 , ./代替 (java.util.Date --> Java/util/Date)。Java的構(gòu)造函數(shù)名稱為固定的<init>名稱 , 通過NewObject()函數(shù)來創(chuàng)建Java對象 。需要注意的是簽名 , 我們可以通過javap -s -p來獲取簽名 。常見簽名如下:

數(shù)據(jù)類型 簽名
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
object L開頭,然后以/分隔的完整類型,后面再加;例如:String類型簽名 Ljava/lang/String
Array 以[開頭,再加上數(shù)組元素的簽名。例如int[]的簽名是 [I , int[][]是[[I

C與Java的字符轉(zhuǎn)換

在開發(fā)中 , 我們常常都會遇到字符編碼問題 , web開發(fā)的時(shí)候 , 時(shí)常需要指定網(wǎng)頁的編碼 , 國內(nèi)一般常用GBK與UTF-8 ,這兩種編碼格式 。 我們在開發(fā)項(xiàng)目的時(shí)候 , 也會指定項(xiàng)目的文件編碼 , 因?yàn)椴煌募幋a對于漢字的支持與處理不同 , GBK采用的是一字節(jié)和雙字節(jié)編碼 , 而UTF-8則采用的是 , 一至四個(gè)字節(jié)編碼 , 單個(gè)字符使用一個(gè)直接表示 , 漢字則使用四個(gè)字節(jié)表示 。

java code

private native String cTransformChar(String str) ;

public static void main(String[] args) {
    HelloJNI jni = new HelloJNI() ;
    System.out.println(jni.cTransformChar("住"));
}

C處理字符編碼

/*C的字符轉(zhuǎn)換*/

JNIEXPORT jstring JNICALL Java_com_zeno_jni_HelloJNI_cTransformChar
(JNIEnv *env, jobject jobj,jstring jStr) {

    // 將jstring轉(zhuǎn)換成c字符指針
    char *cStr = (*env)->GetStringUTFChars(env, jStr, NULL);

    jsize js = (*env)->GetStringLength(env, jStr);


    printf("傳進(jìn)來的值size :  %d\n", js);
    printf("傳進(jìn)來的值 :  %s\n", cStr);

    char destBuffer[50] = "非我 and 小九";

    // 得到String類
    jclass stringCls = (*env)->FindClass(env, "java/lang/String");

    // 得到構(gòu)造方法的ID
    jmethodID stringConstructMid = (*env)->GetMethodID(env, stringCls, "<init>", "([BLjava/lang/String;)V");

    /*
    使用到的Java構(gòu)造方法
    String(byte[] bytes, String charsetName) 
     通過使用指定的 charset 解碼指定的 byte 數(shù)組,構(gòu)造一個(gè)新的 String。
    */

    // 構(gòu)建一個(gè)bytes數(shù)組
    jbyteArray strBytes = (*env)->NewByteArray(env, 50);

    // 設(shè)置字符數(shù)組
    (*env)->SetByteArrayRegion(env, strBytes, 0, strlen(destBuffer), destBuffer);

    // 構(gòu)建字符編碼
    jstring charSetName = (*env)->NewStringUTF(env, "GBK"); 
    // 創(chuàng)建String類的對象
    jstring transformStr = (*env)->NewObject(env, stringCls, stringConstructMid, strBytes, charSetName);

    return transformStr;
}

Tips

如果是使用的eclipse控制臺輸出 , 一定要注意控制臺的字符編碼 , 如果編碼不統(tǒng)一 , 控制臺就會輸出亂碼 ,如:如果要輸出的字符是UTF-8而控制臺是GB2312 , 則會輸出亂碼 。 如果出現(xiàn)亂碼 , 可以將字符寫入到文件中 , 看看是否會亂碼 ,如果亂碼 ,可以使用notepad++看一下文件的編碼 , 如果編碼一致 , 則會顯示正常 。

結(jié)語

這幾天公司產(chǎn)品上線 , 有點(diǎn)忙碌 , 沒多少時(shí)間寫文章 , 今天恢復(fù)寫文章的進(jìn)度。昨天和一個(gè)創(chuàng)業(yè)公司的CEO聊了聊 , 發(fā)現(xiàn)自己欠缺的東西還有很多很多 , 對于產(chǎn)品的架構(gòu) , 如何從0到1 , 將想法轉(zhuǎn)換為產(chǎn)品 , 沒有一個(gè)完整的產(chǎn)品思路 ,也沒有產(chǎn)品經(jīng)理的思維能力,有的只是對界面的吹毛求疵 , 對部分功能的自以為是 。任何行業(yè) , 沒有深入進(jìn)去 , 看的永遠(yuǎn)只是表面 , 都是別人玩剩下的 。

刻意練習(xí)技術(shù) , 時(shí)刻思考產(chǎn)品 。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 現(xiàn)在,你知道了如何通過JNI來訪問JVM中的基本類型數(shù)據(jù)和字符串、數(shù)組這樣的引用類型數(shù)據(jù),下一步就是學(xué)習(xí)怎么樣和J...
    738bc070cd74閱讀 994評論 0 1
  • 接續(xù)上篇JNI開發(fā)系列②.h頭文件分析 前情提要 在前面 , 我們已經(jīng)熟悉了JNI的開發(fā)流程 , .h頭文件的分析...
    逝我閱讀 3,760評論 3 13
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,741評論 18 399
  • D24~3月17日 我有健康的身體,有工作有朋友,有愛我的老公,有一雙可愛的兒女,父母平安健康。 感恩!感恩!感恩...
    sky冬日暖洋洋閱讀 204評論 0 0
  • 《干法》和《活法》兩書是日本的"經(jīng)營之圣"稻盛和夫所寫,他把企業(yè)經(jīng)營上升為哲學(xué)思想,把人生活出一個(gè)新的高度,成就更...
    孫國飛揚(yáng)閱讀 436評論 0 8

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