JNI 案例1-----java調用c方法



  1. 操作環境win10

  2. ide :eclipse和visual Studio 2013


我並不是一個很厲害的程序員,但我知道每天都要進步一點點,所以大傢私信我的時候別說什麼大神之類的話瞭,我很喜歡編程 我隻是把他當成瞭我的愛好,很感謝CSDN這個平臺分享交流的機會,但CSDN手機版app 不知道為什麼點擊博客不是加載不出來就是代碼顯示有問題,一個國內最大交流平臺能一個像樣的app都做不出來?





    • 前言

    • JNI的基本介紹

    • 案例

      • 編寫javanative方法

      • 生成對應c的頭文件XXh

      • 創建對應C工程

      • C代碼函數編寫

      • 生成動態鏈接庫

      • Java加載動態鏈接庫



    • 關於env一級指針和二級指針




前言


我以前在閱讀java源代碼的時候點到某些方法帶有native 然後具體實現沒有

如Object類的 getClass方法


當我第一眼看到的時候 完全不知所以然,後來才知道native修飾方法是非本地java語言方法而是調用c語言.也就是我們常說的jni


JNI的基本介紹


JNI(Java Native Interface) java本地接口,用於c和java語言直接的相互調用.如上面的例子就是java調用c方法


案例


最好的老師就是案例


我們在eclipse創建一個工程 工程中隻有一個文件DemoJni.ava(所在包為com.fmy)

如下圖:


編寫javanative方法


DeemoJni.java源碼:


就隻有一個 getCString方法


生成對應c的頭文件(XX.h)


生成方法:

打開dos窗口

1. cd 你所在工程src目錄下



2. javah 報名.類名


輸入完成後會在src目錄下生成對應的XXX.h文件

生成的文件命名也很有規則:包名類名方法名.h

如下:


我們打開文件看看:


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

#ifndef _Included_com_fmy_DemoJni
#define _Included_com_fmy_DemoJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_fmy_DemoJni
* Method: getCString
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_fmy_DemoJni_getCString
(JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

我們看下核心代碼:


JNIEXPORT jstring JNICALL Java_com_fmy_DemoJni_getCString
(JNIEnv *, jobject, jstring);

這個看起來很眼熟吧?就是我們剛才java寫的對應c方法函數聲明,其命名規則如下 Java_包名_類名(JNIEnv *,jobject,參數…).


註意這裡沒有寫參數變量名,到時候我們需要自己添加上


創建對應C工程


這裡我們創建一個visual studio工程 把剛才剛才頭文件放入工程中


然後在visutal studio添加




選中剛才添加工程目錄的文件




然後打開文件:


可以看到紅色波浪線報錯.

原因是jni.h沒有導入


jni.h位於java安裝目錄下,打開目錄搜索即可看到

以下是我的目錄


C:\Program Files\Java\jdk1.8.0_111\include


可以到jni.h然後像前面添加我們的javah生成的文件一樣添加到工程(先放入工程,然後再visual studio添加)



然後打開com_fmy_Demo.h


 #include<jni.h>改為#include"jni.h"
原因: `<>用於系統的頭文件 ""用於系統和自定義的頭文件`

然後我們打開jni.h文件看看


發現報錯


原因:沒有jni_md.h頭文件


解決辦法:jni_md.h位於 java安裝目錄下

以下是我的目錄


C:\Program Files\Java\jdk1.8.0_111\include\win32


現在解決瞭所有問題 在看一下我們的工程目錄


現在我們開始對應的c代碼吧


C代碼函數編寫


我們在工程創建一個 01.c文件


先導入javah生成的頭文件 本例”com_fmy_DemoJni.h”

1. 所以01.h源碼



#include"com_fmy_DemoJni.h"



2. 復制com_fmy_DemoJni.h中函數聲明到01.c文件中


可以看到編譯報錯

原因:參數沒有寫變量名

解決辦法: 補全參數名(名字看你喜歡)

以下是個人命名:


其中:前面兩個參數 是固定的 ,後面一個 jstring s是我們java聲明的方法參數

我們回頭看看java聲明的:


String JString 參數對應 jstring s


我們繼續看我們c語言的吧,



  1. JNIEnv *env 一個及其重要的參數 Env 是environment(環境)縮寫,那麼直接翻譯就是 java本地接口環境,本質是一個結構體指針,在c環境是2級指針,在c++是一級指針(後面詳解為什麼有區別,先簡單瞭解c++有this關鍵即可). env保存的結構體內含多種實現好的方法,和java和c語言基本數據類型轉換和生成String字符串等.


然後繼續寫完代碼吧


#include"com_fmy_DemoJni.h"

JNIEXPORT jstring JNICALL Java_com_fmy_DemoJni_getCString
(JNIEnv *env, jobject jobj, jstring s){

//用結構體的方法 生成對應java的字符串返回
return (*env)->NewStringUTF(env,"這個是來自C語言");

}

生成動態鏈接庫


windows中是dll文件, 在linux是so文件

我們來看看怎麼做吧:







最後點擊確認



然後在你項目的x64目錄的Debug目錄會有對應dll


Java加載動態鏈接庫



看看運行結果:


亂碼?


解決辦法: 我們前面的01.c保存文件編碼改為UTF-8即可



確定後保存文件!!!記得按下ctrl+s保存文件然後重新生成解決方案即可


運行結果:



關於env一級指針和二級指針


前面我們說env在c中是二級指針 ,在c++中env是二級指針.那麼我們看看為什麼吧.


假設Xiaoming去網吧打遊戲對吧?然後萬一突然電腦壞瞭那麼需要換一臺繼續嗨i.


那麼我以萬物皆對象思想來分析到c中. 假設電腦是一個結構體computer.

Xiaoming是指針指向電腦內存

computer中有一個playgame需要傳入Xiaoming指針的地址,和玩遊戲兩個參數方法,為什麼要傳入Xiaoming指針的地址?因為一旦playgame途中電腦壞瞭,那麼需要重新換電腦對吧?那麼就需要重新創建一個computer然後讓Xiaoming重新指向另一個結構體 ,所以為瞭完成Xiaoming重新指向,所以註定瞭Xiaoming是一個二級指針,而C++有this關鍵字 所以不言而喻……


#include<stdio.h>

//網吧
struct cybercafe
{
void(*play_game)(struct MyStruct **a,char * game_name);

};

//用於實現cybercafe的play_game 函數,如果玩到一半電腦壞瞭那麼需要直接更換電腦
//為瞭防止電腦壞瞭 換機的可能 需要傳入指針地址,讓其指針重新指向另一個電腦,
//那麼我們就需要二級指針保存這個原來指針
void play_game(struct MyStruct **a, char * game_name){

//玩遊戲中
//XXXXXX
//XXXXXX
//XXXXXX

//電腦藍屏奔潰
//fuck 0x66666666
//fuck 0x66666666

//開啟一個新電腦電腦
struct cybercafe computer2;
//換機
*a = &computer2;
}

void main(){

//假設我們創建 一個網吧類型cybercafe 內部隻有一個paly_game函數 ,當我們玩遊戲到一半電腦壞瞭 那麼我就需要換電腦吧?
//這裡就像當於這個結構體壞瞭 ,要出一個新的結構體 ,讓小明這個指針重新指向另一個電腦

//xiaoming開啟一個電腦 上網擼管
struct cybercafe computer1 = { play_game };
//xiaoming 輸入上網賬號到這個computer1上網
struct cybercafe *xiaoming = &computer1;
//小明開始玩遊戲 大傢覺不覺得寫一個取地址很難受?寫到這裡我想大傢應該想知道我想表達什麼瞭
xiaoming->play_game(&xiaoming,"LOL英雄聯盟");

getchar();
}

0 個評論

要回覆文章請先登錄註冊