JNI 學(xué)習(xí)筆記(一)-- jni函數(shù)調(diào)用流程,JNI理解和基本數(shù)據(jù)類型

版權(quán)聲明:著作權(quán)歸作者所有诱担。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)窑滞,非商業(yè)轉(zhuǎn)載請注明出處琼牧。
我的CSDN地址:http://blog.csdn.net/urrjdg
本文CSDN地址:http://blog.csdn.net/urrjdg/article/details/78153147
CSDN 和 簡書 同步更新

看目錄去CSDN

1.介紹 - JNI/NDK/靜態(tài)庫/動態(tài)庫

1.JNI

java native interface
Java中定義的一種用于連接Java和C/C++接口的一種實現(xiàn)方式
使用環(huán)境:
java api 不能滿足我們程序的需要的時候恢筝。
算法計算,圖像渲染 效率要求非常高障陶,
當(dāng)需要訪問一些已有的本地庫

2.NDK

Native Development Kit
工具的集合滋恬。幫助開放者快速開放C/C++ 動態(tài)庫的工具。
是Google在Android開發(fā)中提供的一套用于快速創(chuàng)建native工程的一個工具抱究。使用這個工具可以很方便的編寫恢氯,調(diào)試JNI的代碼。

3.靜態(tài)庫和動態(tài)庫

都是函數(shù)庫鼓寺。
靜態(tài)庫:.a (靜態(tài)庫在程序編譯的時候就會直接連接到目標(biāo)代碼里面勋拟,所以在運(yùn)行的時候就不需要了 )
動態(tài)庫: .dll/.so (動態(tài)庫在編譯的時候不會自動連接到目標(biāo)代碼里面,就是說 這個動態(tài)庫是獨(dú)立吧妈候,不會隨著程序的編譯直接鏈接進(jìn)去敢靡,而是在程序運(yùn)行的時候動態(tài)加載的,例如一下代碼)

// 只有在運(yùn)行工程的時候才會去走 這個static的代碼塊苦银,這就是動態(tài)的過程     
static{
    System.loadLibrary("JNI_Native");
}

好處:功能獨(dú)立啸胧,作為方案提供商不需要提供源碼(保密)

4.JNIEnv 是什么?

C:
JNIEnv 結(jié)構(gòu)體指針的別名
env 是二級指針

C++
JNIEnv 是結(jié)構(gòu)體的別名
env 是一級指針

每個native 函數(shù)幔虏,都至少有兩個參數(shù)(JNIEnv * , jclass/jobject)
jclass: native 靜態(tài)方法
jobject: native 非靜態(tài)方法

5. 數(shù)據(jù)類型

Jni基本數(shù)據(jù)類型

基本數(shù)據(jù)類型

引用類型

String jstring在·
Object jobject

引用類型

基本數(shù)據(jù)類型數(shù)組:

//type[] jTypeArray;
byte[] jByteArray;

引用類型數(shù)組

Object jobjectArray;

6. 屬性簽名

屬性簽名

例如:Java方法:

long f(int n,String s,int[] arr);

具有以下類型簽名:

(ILjava/lang/String;[I)J

2. 使用jni 進(jìn)行 java 調(diào)用 C 的 靜態(tài) 和非靜態(tài)navtive方法

1. 新建一個 Java工程


public class JniTest01 {

    // 靜態(tài)方法
    public native static String getStringFromC();
    // 非靜態(tài)方法
    public native String getStringFromC2();
    
    public static void main(String[] args) {
        System.out.println("Test01");
    }
    
}

2. 使用 javah 命令

使用 cmd 跳轉(zhuǎn)到 JniTest01這個類 的當(dāng)前 目錄下 纺念,直接敲 javah ,生成 JniTest01.h 文件( 或者自己手寫:java_類的全名_方法名)

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class JniTest01 */

#ifndef _Included_JniTest01
#define _Included_JniTest01
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JniTest01
 * Method:    getStringFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_JniTest01_getStringFromC
  (JNIEnv *, jclass);

/*
 * Class:     JniTest01
 * Method:    getStringFromC2
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_JniTest01_getStringFromC2
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

3. 復(fù)制.h 頭文件到cpp 工程 (Vistual Studio)

復(fù)制 .h 文件的 時候要先拷貝到 工程所在的頭文件夾下面想括, 然后在 visual studio的工程那邊 : 頭文件右鍵 添加--》 現(xiàn)有項

4. 復(fù)制jni.h 和jni_md.h

同上

jni.hjni_md.h

C:\develop\Java\jdk1.8.0_111\include
C:\develop\Java\jdk1.8.0_111\include\win32

記得修改 JniMain.h#include <jni.h>#include "jni.h"

5. 實現(xiàn).h 頭文件中的聲明函數(shù)

這是個C文件 不是Cpp陷谱,先用C進(jìn)行演示,后面的系列會用到C++

#include "JniTest01.h"
#include "stdafx.h"
/*
* Class:     JniTest01
* Method:    getStringFromC
* Signature: ()Ljava/lang/String;
*/
// 靜態(tài)方法 jclass
JNIEXPORT jstring JNICALL Java_JniTest01_getStringFromC
(JNIEnv * env, jclass jclz){
    return(*env)->NewStringUTF(env,"String frome C 01,ZekingLee");
}

/*
* Class:     JniTest01
* Method:    getStringFromC2
* Signature: ()Ljava/lang/String;
*/
// 非靜態(tài)方法 jobject
JNIEXPORT jstring JNICALL Java_JniTest01_getStringFromC2
(JNIEnv * env, jobject jclz){
    return(*env)->NewStringUTF(env, "String frome C 02,ZekingLee");
}

6. 生成一個dll 動態(tài)庫

右鍵 visual studio 的項目名 --》 屬性 --》 配置屬性 --》 常規(guī) --》 配置類型 --》 動態(tài)庫(.dll)

平臺使用x64

如果出現(xiàn) : 錯誤 1 error C1083: 無法打開預(yù)編譯頭文件: “x64\Debug\ConsoleApplication1.pch”: No such file or directory C:\Users\Zeking\Desktop\JNICode\Jni01\ConsoleApplication1\ConsoleApplication1\JniTest01.c 2 1 ConsoleApplication1

右鍵工程名字-->屬性-->配置屬性-->C/C++ -->預(yù)編譯頭--> 選擇不適用預(yù)編譯頭

7. 在java中加載動態(tài)庫

dll文件 復(fù)制到 java工程里面

8. 觸發(fā)native函數(shù)


public class JniTest01 {

    // 靜態(tài)方法
    public native static String getStringFromC();
    // 非靜態(tài)方法
    public native String getStringFromC2();
    
    public static void main(String[] args) {
        System.out.println(getStringFromC());  // 輸出  String frome C 01,ZekingLee
        
        JniTest01 jinTest01 = new JniTest01();
        System.out.println(jinTest01.getStringFromC2()); // 輸出  String frome C 02,ZekingLee
         
    }
    
    static{
        System.loadLibrary("ConsoleApplication1");
    }
    
}

3. 使用jni 進(jìn)行C 調(diào)用 java 的 靜態(tài) 和非靜態(tài)變量

遇到這個錯誤的解決方法:

error C4996: 'strcat': This function or variable may be unsafe. Consider using strcat_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. C:\Users\Zeking\Desktop\JNICode\Jni01\ConsoleApplication1\ConsoleApplication1\JniTest01.c 51 1 ConsoleApplication1

項目名右鍵--> 屬性-->C/C++-->預(yù)處理器-->預(yù)處理定義 添加 _CRT_SECURE_NO_WARNINGS

public class JniTest02 {
    // 非靜態(tài)變量
    public String key = "Key";
    // 靜態(tài)變量
    public static int count = 99;
    // 調(diào)用非靜態(tài)變量
    public native String accessField();
    // 調(diào)用靜態(tài)變量
    public native void accessStaticField();
    
    static{
        System.loadLibrary("ConsoleApplication1");
    }
    
    public static void main(String[] args) {
        

        JniTest02 jniTest02 = new JniTest02();
        System.out.println(jniTest02.key);  // Key
        jniTest02.accessField();
        System.out.println(jniTest02.key);  // ZekingKey
        
        System.out.println(count);          // 99
        jniTest02.accessStaticField();
        System.out.println(count);          // 100
        
    }

}

#include "JniTest02.h"
#include "stdafx.h"
#include <string.h>
#include <stdio.h>

/*
* Class:     JniTest02
* Method:    accessField
* Signature: ()Ljava/lang/String;
* 
*/
// 訪問非靜態(tài)域 
JNIEXPORT jstring JNICALL Java_JniTest02_accessField
(JNIEnv * env, jobject jobj){
    // jclass
    jclass jclz = (*env)->GetObjectClass(env, jobj);

    // fieldId 屬性名稱,屬性簽名
    jfieldID fid = (*env)->GetFieldID(env, jclz, "key", "Ljava/lang/String;");
    // key -> dongNao key

    // 得到key 對應(yīng)的值
    // GetXXXField
    jstring jstr = (*env)->GetObjectField(env, jobj, fid);

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

    char text[30] = "Zeking";
    // 生成新的字符串 ZekingKey
    strcat(text, c_str);

    // C -> jni
    jstring new_str = (*env)->NewStringUTF(env, text);

    //setXXXField
    (*env)->SetObjectField(env, jobj, fid, new_str);

    (*env)->ReleaseStringChars(env, new_str, c_str);

    return new_str;
}

/*
* Class:     JniTest02
* Method:    accessStaticField
* Signature: ()V
*/
// 訪問靜態(tài)域
JNIEXPORT void JNICALL Java_JniTest02_accessStaticField
(JNIEnv * env, jobject jobj){

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

    jfieldID fid = (*env)->GetStaticFieldID(env, jclz, "count", "I");

    if (fid == NULL){
        printf("fid is Null");
    }

    jint count = (*env)->GetStaticIntField(env, jclz, fid);
    count++;

    (*env)->SetStaticIntField(env, jclz, fid, count);



}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瑟蜈,一起剝皮案震驚了整個濱河市烟逊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铺根,老刑警劉巖宪躯,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異夷都,居然都是意外死亡眷唉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門囤官,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冬阳,“玉大人,你說我怎么就攤上這事党饮「闻悖” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵刑顺,是天一觀的道長氯窍。 經(jīng)常有香客問我饲常,道長,這世上最難降的妖魔是什么狼讨? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任贝淤,我火速辦了婚禮,結(jié)果婚禮上政供,老公的妹妹穿的比我還像新娘播聪。我一直安慰自己,他們只是感情好布隔,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布离陶。 她就那樣靜靜地躺著,像睡著了一般衅檀。 火紅的嫁衣襯著肌膚如雪招刨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天哀军,我揣著相機(jī)與錄音沉眶,去河邊找鬼。 笑死杉适,一個胖子當(dāng)著我的面吹牛沦寂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播淘衙,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼腻暮!你這毒婦竟也來了彤守?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤哭靖,失蹤者是張志新(化名)和其女友劉穎具垫,沒想到半個月后寒波,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體边苹,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年饺饭,在試婚紗的時候發(fā)現(xiàn)自己被綠了铺坞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片起宽。...
    茶點(diǎn)故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖济榨,靈堂內(nèi)的尸體忽然破棺而出坯沪,到底是詐尸還是另有隱情,我是刑警寧澤擒滑,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布腐晾,位于F島的核電站叉弦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏藻糖。R本人自食惡果不足惜淹冰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望巨柒。 院中可真熱鬧樱拴,春花似錦、人聲如沸潘拱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芦岂。三九已至瘪弓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間禽最,已是汗流浹背腺怯。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留川无,地道東北人呛占。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像懦趋,于是被迫代替她去往敵國和親晾虑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容