亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

java的JNI本地調用代碼

系統 1752 0

Jni中C++和Java的參數傳遞

如何使用JNI的一些基本方法和過程在網上多如牛毛,如果你對Jni不甚了解,不知道Jni是做什么的,如何建立一個基本的jni程序,或許可以參考下面下面這些文章:
利用VC++6.0實現JNI的最簡單的例子 ?
JNI入門教程之HelloWorld篇
SUN JNI Tutorial

這些資料的例子中,大多數只是輸入一些簡單的參數,獲取沒有參數。而在實際的使用過程中,往往需要對參數進行處理轉換。才可以被C/C++程序識別。比如我們在C++中有一個結構(Struct)DiskInfo ,需要傳遞一個類似于DiskInfo *pDiskInfo的參數,類似于在C++這樣參數如何傳遞到Java中呢?下面我們就來討論C++到Java中方法的一些常見參數的轉換:

定義Native Java類:

如果你習慣了使用JNI,你就不會覺得它難了。既然本地方法是由其他語言實現的,它們在Java中沒有函數體。但是,所有本地代碼必須用本地關鍵詞聲明,成為Java類的成員。假設我們在C++中有這么一個結構,它用來描述硬盤信息:

// 硬盤信息
struct ?? {
????
char ?name[ 256 ];
????
int ?serial;
}
DiskInfo;

那么我們需要在Java中定義一個類來與之匹配,聲明可以寫成這樣:

class ?DiskInfo? {
????
// 名字
???? public ?String?name;

????
// 序列號
???? public ? int ?serial;
}

在這個類中,申明一些Native的本地方法,來測試方法參數的傳遞,分別定義了一些函數,用來傳遞結構或者結構數組,具體定義如下面代碼:

/**/ /* *****************?定義本地方法?******************* */
????
// 輸入常用的數值類型(Boolean,Byte,Char,Short,Int,Float,Double)
???? public ?native? void ?displayParms(String?showText,? int ?i,?boolean?bl);

????
// 調用一個靜態方法
???? public ?native? int ?add( int ?a,? int ?b);

????
// 輸入一個數組
???? public ?native? void ?setArray(boolean[]?blList);

????
// 返回一個字符串數組
???? public ?native?String[]?getStringArray();

????
// 返回一個結構
???? public ?native?DiskInfo?getStruct();

????
// 返回一個結構數組
???? public ?native?DiskInfo[]?getStructArray();

編譯生成C/C++頭文件

定義好了Java類之后,接下來就要寫本地代碼。本地方法符號提供一個滿足約定的頭文件,使用 Java工具Javah 可以很容易地創建它而不用手動去創建。你對Java的class文件使用javah命令,就會為你生成一個對應的C/C++頭文件。
1、在控制臺下進入工作路徑,本工程路徑為:E:\work\java\workspace\JavaJni。
2、運行javah 命令:javah -classpath E:\work\java\workspace\JavaJni com.sundy.jnidemo ChangeMethodFromJni
本文生成的C/C++頭文件名為: com_sundy_jnidemo_ChangeMethodFromJni.h?

在C/C++中實現本地方法

生成C/C++頭文件之后,你就需要寫頭文件對應的本地方法。注意:所有的本地方法的第一個參數都是指向 JNIEnv 結構的。這個結構是用來調用JNI函數的。第二個參數jclass的意義,要看方法是不是靜態的(static)或者實例(Instance)的。前者,jclass代表一個類對象的引用,而后者是被調用的方法所屬對象的引用。

?

返回值和參數類型 根據等價約定映射到本地C/C++類型,如表 JNI類型映射 所示。有些類型,在本地代碼中可直接使用,而其他類型只有通過JNI調用操作。

表A

Java 類型 本地類型 描述
boolean jboolean C/C++8位整型
byte jbyte C/C++帶符號的8位整型
char jchar C/C++無符號的16位整型
short jshort C/C++帶符號的16位整型
int jint C/C++帶符號的32位整型
long jlong C/C++帶符號的64位整型e
float jfloat C/C++32位浮點型
double jdouble C/C++64位浮點型
Object jobject 任何Java對象,或者沒有對應java類型的對象
Class jclass Class對象
String jstring 字符串對象
Object[] jobjectArray 任何對象的數組
boolean[] jbooleanArray 布爾型數組
byte[] jbyteArray 比特型數組
char[] jcharArray 字符型數組
short[] jshortArray 短整型數組
int[] jintArray 整型數組
long[] jlongArray 長整型數組
float[] jfloatArray 浮點型數組
double[] jdoubleArray 雙浮點型數組

※???? JNI類型映射

使用數組:

JNI通過JNIEnv提供的操作Java數組的功能。它提供了兩個函數:一個是操作java的簡單型數組的,另一個是操作對象類型數組的。

因為速度的原因,簡單類型的數組作為指向本地類型的指針暴露給本地代碼。因此,它們能作為常規的數組存取。這個指針是指向實際的Java數組或者Java數組的拷貝的指針。另外,數組的布置保證匹配本地類型。

為了存取Java簡單類型的數組,你就要要使用 GetXXXArrayElements 函數(見 B ),XXX代表了數組的類型。這個函數把Java數組看成參數,返回一個指向對應的本地類型的數組的指針。

表B

函數 Java 數組類型 本地類型
GetBooleanArrayElements jbooleanArray jboolean
GetByteArrayElements jbyteArray jbyte
GetCharArrayElements jcharArray jchar
GetShortArrayElements jshortArray jshort
GetIntArrayElements jintArray jint
GetLongArrayElements jlongArray jlong
GetFloatArrayElements jfloatArray jfloat
GetDoubleArrayElements jdoubleArray jdouble

JNI數組存取函數

當你對數組的存取完成后,要確保調用相應的 ReleaseXXXArrayElements 函數,參數是對應Java數組和 GetXXXArrayElements 返回的指針。如果必要的話,這個釋放函數會復制你做的任何變化(這樣它們就反射到java數組),然后釋放所有相關的資源。

為了使用java對象的數組,你必須使用 GetObjectArrayElement 函數和 SetObjectArrayElement 函數,分別去get,set數組的元素。 GetArrayLength 函數會返回數組的長度。

使用對象

JNI提供的另外一個功能是在本地代碼中使用Java對象。通過使用合適的JNI函數,你可以創建Java對象,get、set 靜態(static)和實例(instance)的域,調用靜態(static)和實例(instance)函數。JNI通過ID識別域和方法,一個域或方法的ID是任何處理域和方法的函數的必須參數。

表C 列出了用以得到靜態(static)和實例(instance)的域與方法的JNI函數。每個函數接受(作為參數)域或方法的類,它們的名稱,符號和它們對應返回的 jfieldID jmethodID

表C

函數 描述
GetFieldID 得到一個實例的域的ID
GetStaticFieldID 得到一個靜態的域的ID
GetMethodID 得到一個實例的方法的ID
GetStaticMethodID 得到一個靜態方法的ID

※域和方法的函數

如果你有了一個類的實例,它就可以通過方法 GetObjectClass 得到,或者如果你沒有這個類的實例,可以通過 FindClass 得到。符號是從域的類型或者方法的參數,返回值得到字符串,如 D 所示。

表D

Java 類型 符號
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
objects對象 Lfully-qualified-class-name;L類名
Arrays數組 [array-type [數組類型
methods方法 (argument-types)return-type(參數類型)返回類型

※確定域和方法的符號


下面我們來看看,如果通過使用數組和對象,從C++中的獲取到Java中的DiskInfo 類對象,并返回一個DiskInfo數組:

// 返回一個結構數組,返回一個硬盤信息的結構數組
JNIEXPORT?jobjectArray?JNICALL?Java_com_sundy_jnidemo_ChangeMethodFromJni_getStructArray
(JNIEnv?
* env,?jobject?_obj)
{
????
// 申明一個object數組?
????jobjectArray?args? = ? 0 ;
????
????
// 數組大小
????jsize????????len? = ? 5 ;

????
// 獲取object所屬類,一般為ava/lang/Object就可以了
????jclass?objClass? = ?(env) -> FindClass( " java/lang/Object " );

????
// 新建object數組
????args? = ?(env) -> NewObjectArray(len,?objClass,? 0 );

????
/**/ /* ?下面為獲取到Java中對應的實例類中的變量 */

????
// 獲取Java中的實例類
????jclass?objectClass? = ?(env) -> FindClass( " com/sundy/jnidemo/DiskInfo " );
????
????
// 獲取類中每一個變量的定義
????
// 名字
????jfieldID?str? = ?(env) -> GetFieldID(objectClass, " name " , " Ljava/lang/String; " );
????
// 序列號
????jfieldID?ival? = ?(env) -> GetFieldID(objectClass, " serial " , " I " );

????
// 給每一個實例的變量付值,并且將實例作為一個object,添加到objcet數組中
???? for ( int ??i = 0 ;?i? < ?len;?i ++ ?)
????
{
????????
// 給每一個實例的變量付值
????????jstring?jstr? = ?WindowsTojstring(env, " 我的磁盤名字是?D: " );
????????
// (env)->SetObjectField(_obj,str,(env)->NewStringUTF("my?name?is?D:"));
????????(env) -> SetObjectField(_obj,str,jstr);
????????(env)
-> SetShortField(_obj,ival, 10 );

????????
// 添加到objcet數組中
????????(env) -> SetObjectArrayElement(args,?i,?_obj);
????}

????
// 返回object數組
???? return ?args;

?}



全部的C/C++方法實現代碼如下:

/**/ /*
*
*?一縷陽光(sundy)版權所有,保留所有權利。
*/

/**/ /* *
*?
*??TODO?Jni?中一個從Java到C/C++參數傳遞測試類
*
*??@author?劉正偉(sundy)
*??@see?
http://www.cnweblog.com/sundy
*??@see?mailto:sundy26@126.com
*??@version?1.0
*??@since?2005-4-30
*?
*??修改記錄:
*??
*??日期??????????????修改人?????????????????描述
*??----------------------------------------------------------------------------------------------
*
*
*
*/

// ?JniManage.cpp?:?定義?DLL?應用程序的入口點。
//
package?com.sundy.jnidemo;
#include?
" stdafx.h "

#include?
< stdio.h >
#include?
< math.h >
#include?
" jni.h "
#include?
" jni_md.h "

#include?
" ./head/Base.h "
#include?
" head/wmi.h "
#include?
" head/com_sundy_jnidemo_ChangeMethodFromJni.h " ? // 通過javah?–jni?javactransfer?生成
#include? < stdio.h >
#include?
" stdlib.h "
#include?
" string.h "

#pragma?comment?(lib,
" BaseInfo.lib " )
#pragma?comment?(lib,
" jvm.lib " )
// 硬盤信息
struct ?? {
????
char ?name[ 256 ];
????
int ?serial;
}
DiskInfo;
/**/ /* BOOL?APIENTRY?DllMain(?HANDLE?hModule,?
???????????????????????DWORD??ul_reason_for_call,?
???????????????????????LPVOID?lpReserved
?????????????????????)
{
????LPTSTR??strName?=?new?CHAR[256]?;
????(*GetHostName)(strName);
????printf("%s\n",strName);
????delete?[]?strName;

????return?TRUE;
}
*/

// 將jstring類型轉換成windows類型
char * ?jstringToWindows(?JNIEnv? * env,?jstring?jstr?);
// 將windows類型轉換成jstring類型
jstring?WindowsTojstring(?JNIEnv * ?env,? char * ?str?);

// 主函數
BOOL?WINAPI?DllMain(HANDLE?hHandle,?DWORD?dwReason,?LPVOID?lpReserved)
{
????
return ?TRUE;
}

// 輸入常用的數值類型?Boolean,Byte,Char,Short,Int,Float,Double
JNIEXPORT? void ?JNICALL?Java_com_sundy_jnidemo_ChangeMethodFromJni_displayParms
(JNIEnv?
* env,?jobject?obj,?jstring?s,?jint?i,?jboolean?b)
{
????
const ? char * ?szStr? = ?(env) -> GetStringUTFChars(s,? 0 ?);
????printf(?
" String?=?[%s]\n " ,?szStr?);
????printf(?
" int?=?%d\n " ,?i?);
????printf(?
" boolean?=?%s\n " ,?(b == JNI_TRUE? ? ? " true " ?:? " false " )?);
????(env)
-> ReleaseStringUTFChars(s,?szStr?);
}


// 調用一個靜態方法,只有一個簡單類型輸出
JNIEXPORT?jint?JNICALL?Java_com_sundy_jnidemo_ChangeMethodFromJni_add
(JNIEnv?
* env,?jobject,?jint?a,?jint?b)
{
????
int ?rtn? = ?( int )(a? + ?b);
????
return ?(jint)rtn;
}


/**/ /// /輸入一個數組,這里輸入的是一個Boolean類型的數組
JNIEXPORT? void ?JNICALL?Java_com_sundy_jnidemo_ChangeMethodFromJni_setArray
(JNIEnv?
* env,?jobject,?jbooleanArray?ba)
{
????jboolean
* ?pba? = ?(env) -> GetBooleanArrayElements(ba,? 0 ?);
????jsize?len?
= ?(env) -> GetArrayLength(ba);
????
int ?i = 0 ;
????
// ?change?even?array?elements
???? for (?i = 0 ;?i? < ?len;?i += 2 ?)
????
{
????????pba[i]?
= ?JNI_FALSE;
????????printf(?
" boolean?=?%s\n " ,?(pba[i] == JNI_TRUE? ? ? " true " ?:? " false " )?);
????}

????(env)
-> ReleaseBooleanArrayElements(ba,?pba,? 0 ?);
}


/**/ /// /返回一個字符串數組
JNIEXPORT?jobjectArray?JNICALL?Java_com_sundy_jnidemo_ChangeMethodFromJni_getStringArray
(JNIEnv?
* env,?jobject)
{
????jstring??????str;
????jobjectArray?args?
= ? 0 ;
????jsize????????len?
= ? 5 ;
????
char * ????????sa[]? = ? {? " Hello, " ,? " world! " ,? " JNI " ,? " is " ,? " fun " ?} ;
????
int ??????????i = 0 ;
????args?
= ?(env) -> NewObjectArray(len,(env) -> FindClass( " java/lang/String " ), 0 );
????
for (?i = 0 ;?i? < ?len;?i ++ ?)
????
{
????????str?
= ?(env) -> NewStringUTF(sa[i]?);
????????(env)
-> SetObjectArrayElement(args,?i,?str);
????}

????
return ?args;
}


// 返回一個結構,這里返回一個硬盤信息的簡單結構類型
JNIEXPORT?jobject?JNICALL?Java_com_sundy_jnidemo_ChangeMethodFromJni_getStruct
(JNIEnv?
* env,?jobject?obj)
{
????
/**/ /* ?下面為獲取到Java中對應的實例類中的變量 */

????
// 獲取Java中的實例類
????jclass?objectClass? = ?(env) -> FindClass( " com/sundy/jnidemo/DiskInfo " );

????
// 獲取類中每一個變量的定義
????
// 名字
????jfieldID?str? = ?(env) -> GetFieldID(objectClass, " name " , " Ljava/lang/String; " );
????
// 序列號
????jfieldID?ival? = ?(env) -> GetFieldID(objectClass, " serial " , " I " );


????
// 給每一個實例的變量付值
????(env) -> SetObjectField(obj,str,(env) -> NewStringUTF( " my?name?is?D: " ));
????(env)
-> SetShortField(obj,ival, 10 );
????
????
return ?obj;
}


// 返回一個結構數組,返回一個硬盤信息的結構數組
JNIEXPORT?jobjectArray?JNICALL?Java_com_sundy_jnidemo_ChangeMethodFromJni_getStructArray
(JNIEnv?
* env,?jobject?_obj)
{
????
// 申明一個object數組?
????jobjectArray?args? = ? 0 ;
????
????
// 數組大小
????jsize????????len? = ? 5 ;

????
// 獲取object所屬類,一般為ava/lang/Object就可以了
????jclass?objClass? = ?(env) -> FindClass( " java/lang/Object " );

????
// 新建object數組
????args? = ?(env) -> NewObjectArray(len,?objClass,? 0 );

????
/**/ /* ?下面為獲取到Java中對應的實例類中的變量 */

????
// 獲取Java中的實例類
????jclass?objectClass? = ?(env) -> FindClass( " com/sundy/jnidemo/DiskInfo " );
????
????
// 獲取類中每一個變量的定義
????
// 名字
????jfieldID?str? = ?(env) -> GetFieldID(objectClass, " name " , " Ljava/lang/String; " );
????
// 序列號
????jfieldID?ival? = ?(env) -> GetFieldID(objectClass, " serial " , " I " );

????
// 給每一個實例的變量付值,并且將實例作為一個object,添加到objcet數組中
???? for ( int ??i = 0 ;?i? < ?len;?i ++ ?)
????
{
????????
// 給每一個實例的變量付值
????????jstring?jstr? = ?WindowsTojstring(env, " 我的磁盤名字是?D: " );
????????
// (env)->SetObjectField(_obj,str,(env)->NewStringUTF("my?name?is?D:"));
????????(env) -> SetObjectField(_obj,str,jstr);
????????(env)
-> SetShortField(_obj,ival, 10 );

????????
// 添加到objcet數組中
????????(env) -> SetObjectArrayElement(args,?i,?_obj);
????}

????
// 返回object數組
???? return ?args;

?}


// 將jstring類型轉換成windows類型
char * ?jstringToWindows(?JNIEnv?? * env,?jstring?jstr?)
{
????
int ?length? = ?(env) -> GetStringLength(jstr?);
????
const ?jchar * ?jcstr? = ?(env) -> GetStringChars(jstr,? 0 ?);
????
char * ?rtn? = ?( char * )malloc(?length * 2 + 1 ?);
????
int ?size? = ? 0 ;
????size?
= ?WideCharToMultiByte(?CP_ACP,? 0 ,?(LPCWSTR)jcstr,?length,?rtn,(length * 2 + 1 ),?NULL,?NULL?);
????
if (?size? <= ? 0 ?)
????????
return ?NULL;
????(env)
-> ReleaseStringChars(jstr,?jcstr?);
????rtn[size]?
= ? 0 ;
????
return ?rtn;
}

// 將windows類型轉換成jstring類型
jstring?WindowsTojstring(?JNIEnv * ?env,? char * ?str?)
{
????jstring?rtn?
= ? 0 ;
????
int ?slen? = ?strlen(str);
????unsigned?
short ? * ?buffer? = ? 0 ;
????
if (?slen? == ? 0 ?)
????????rtn?
= ?(env) -> NewStringUTF(str?);?
????
else
????
{
????????
int ?length? = ?MultiByteToWideChar(?CP_ACP,? 0 ,?(LPCSTR)str,?slen,?NULL,? 0 ?);
????????buffer?
= ?(unsigned? short ? * )malloc(?length * 2 ? + ? 1 ?);
????????
if (?MultiByteToWideChar(?CP_ACP,? 0 ,?(LPCSTR)str,?slen,?(LPWSTR)buffer,?length?)? > 0 ?)
????????????rtn?
= ?(env) -> NewString(??(jchar * )buffer,?length?);
????}

????
if (?buffer?)
????????free(?buffer?);
????
return ?rtn;
}


Java 測試native代碼
這沒有什么多說的,看代碼吧

// 主測試程序
???? public ? static ? void ?main(String[]?args)? {
????????ChangeMethodFromJni?changeJni?
= ? new ?ChangeMethodFromJni();

????????
// 輸入常用的數值類型(string?int?boolean)
????????System. out
????????????????.println(
" ------------------輸入常用的數值類型(string?int?boolean)----------- " );
????????changeJni.displayParms(
" Hello?World! " ,? 100 ,? true );

????????
// 調用一個靜態方法
????????System. out .println( " ------------------調用一個靜態方法----------- " );
????????
int ?ret? = ?changeJni.add( 12 ,? 20 );
????????System.
out .println( " The?result?is:? " ? + ?String.valueOf(ret));

????????
// 輸入一個數組
????????System. out .println( " ------------------輸入一個數組----------- " );
????????boolean[]?blList?
= ? new ?boolean[]? {? true ,? false ,? true ?} ;
????????changeJni.setArray(blList);

????????
// 返回一個字符串數組
????????System. out .println( " ------------------返回一個字符串數組----------- " );
????????String[]?strList?
= ?changeJni.getStringArray();
????????
for ?( int ?i? = ? 0 ;?i? < ?strList.length;?i ++ )? {
????????????System.
out .print(strList[i]);
????????}

????????System.
out .println();

????????System.
out .println( " ------------------返回一個結構----------- " );

????????
// 返回一個結構
????????DiskInfo?disk? = ?changeJni.getStruct();
????????System.
out .println( " name: " ? + ?disk.name);
????????System.
out .println( " Serial: " ? + ?disk.serial);

????????
// 返回一個結構數組

????????System.
out .println( " ------------------返回一個結構數組?----------- " );
????????DiskInfo[]?diskList?
= ?changeJni.getStructArray();
????????
for ?( int ?i? = ? 0 ;?i? < ?diskList.length;?i ++ )? {
????????????System.
out .println( " name: " ? + ?diskList[i].name);
????????????System.
out .println( " Serial: " ? + ?diskList[i].serial);
????????}


????}


注:本程序在VS2003,eclipse (jse5.0) winxp sp2編譯通過

java的JNI本地調用代碼


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产视频毛片 | 夜色精品国产一区二区 | 一区二区三区成人 | 美女被a到爽视频在线观看 美女被cao的视频免费看 | 国产精品亚洲综合一区 | 99爱视频在线观看免费播放 | 四虎影片| 草草国产成人免费视频 | 日韩免费福利视频 | 99爱视频在线 | 精品 日韩 国产 欧美在线观看 | 一级看片免费视频 | 国产五月婷婷 | 一级特黄aaaaaa大片 | 四虎影院在线播放视频 | 国产高清一级视频在线观看 | 欧美高清理论片在线观看 | 色涩在线| 99国产在线观看 | 97se在线观看 | 亚洲一区二区三区中文字幕 | 99热精品久久只有精品30 | 国产精品免费_区二区三区观看 | 97高清国语自产拍 | 免费精品美女久久久久久久久 | 九九色视频在线观看 | 最新国产中文字幕 | 日韩欧美国产一区二区三区四区 | 久久精品国产精品国产精品污 | 国产精品视频一区二区三区 | 四虎影永久在线观看网址 | 九九九精品午夜在线观看 | 综合免费一区二区三区 | 国产综合日韩伦理 | 久久精品a| 四虎成人国产精品视频 | 五月久久亚洲七七综合中文网 | 国产成人综合久久亚洲精品 | 久久这里只有精品国产99 | 亚洲黄色免费看 | 青青热在线精品视频免费 |