小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Jni中C++和Java的數(shù)據(jù)類型的對(duì)應(yīng)關(guān)系

 champion_xu 2015-10-29
Jni中C++和Java的參數(shù)傳遞

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

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

定義Native Java類:

如果你習(xí)慣了使用JNI,你就不會(huì)覺得它難了。既然本地方法是由其他語(yǔ)言實(shí)現(xiàn)的,它們?cè)贘ava中沒有函數(shù)體。但是,所有本地代碼必須用本地關(guān)鍵詞聲明,成為Java類的成員。假設(shè)我們?cè)贑++中有這么一個(gè)結(jié)構(gòu),它用來(lái)描述硬盤信息:

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

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

class  DiskInfo {
    
// 名字
     public String name;

    
// 序列號(hào)
     public int  serial;
}

在這個(gè)類中,申明一些Native的本地方法,來(lái)測(cè)試方法參數(shù)的傳遞,分別定義了一些函數(shù),用來(lái)傳遞結(jié)構(gòu)或者結(jié)構(gòu)數(shù)組,具體定義如下面代碼:

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

    
// 調(diào)用一個(gè)靜態(tài)方法
     public native int add( int  a,  int b);

    
// 輸入一個(gè)數(shù)組
     public native void setArray(boolean[] blList);

    
// 返回一個(gè)字符串?dāng)?shù)組
     public native String[] getStringArray();

    
// 返回一個(gè)結(jié)構(gòu)
     public native DiskInfo getStruct();

    
// 返回一個(gè)結(jié)構(gòu)數(shù)組
     public native DiskInfo[] getStructArray();

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

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

在C/C++中實(shí)現(xiàn)本地方法

生成C/C++頭文件之后,你就需要寫頭文件對(duì)應(yīng)的本地方法。注意:所有的本地方法的第一個(gè)參數(shù)都是指向JNIEnv結(jié)構(gòu)的。這個(gè)結(jié)構(gòu)是用來(lái)調(diào)用JNI函數(shù)的。第二個(gè)參數(shù)jclass的意義,要看方法是不是靜態(tài)的(static)或者實(shí)例(Instance)的。前者,jclass代表一個(gè)類對(duì)象的引用,而后者是被調(diào)用的方法所屬對(duì)象的引用。

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

表A

Java 類型本地類型描述
booleanjbooleanC/C++8位整型
bytejbyteC/C++帶符號(hào)的8位整型
charjcharC/C++無(wú)符號(hào)的16位整型
shortjshortC/C++帶符號(hào)的16位整型
intjintC/C++帶符號(hào)的32位整型
longjlongC/C++帶符號(hào)的64位整型e
floatjfloatC/C++32位浮點(diǎn)型
doublejdoubleC/C++64位浮點(diǎn)型
Objectjobject任何Java對(duì)象,或者沒有對(duì)應(yīng)java類型的對(duì)象
ClassjclassClass對(duì)象
Stringjstring字符串對(duì)象
Object[]jobjectArray任何對(duì)象的數(shù)組
boolean[]jbooleanArray布爾型數(shù)組
byte[]jbyteArray比特型數(shù)組
char[]jcharArray字符型數(shù)組
short[]jshortArray短整型數(shù)組
int[]jintArray整型數(shù)組
long[]jlongArray長(zhǎng)整型數(shù)組
float[]jfloatArray浮點(diǎn)型數(shù)組
double[]jdoubleArray雙浮點(diǎn)型數(shù)組

※     JNI類型映射

使用數(shù)組:

JNI通過(guò)JNIEnv提供的操作Java數(shù)組的功能。它提供了兩個(gè)函數(shù):一個(gè)是操作java的簡(jiǎn)單型數(shù)組的,另一個(gè)是操作對(duì)象類型數(shù)組的。

因?yàn)樗俣鹊脑颍?jiǎn)單類型的數(shù)組作為指向本地類型的指針暴露給本地代碼。因此,它們能作為常規(guī)的數(shù)組存取。這個(gè)指針是指向?qū)嶋H的Java數(shù)組或者Java數(shù)組的拷貝的指針。另外,數(shù)組的布置保證匹配本地類型。

為了存取Java簡(jiǎn)單類型的數(shù)組,你就要要使用GetXXXArrayElements函數(shù)(見表B),XXX代表了數(shù)組的類型。這個(gè)函數(shù)把Java數(shù)組看成參數(shù),返回一個(gè)指向?qū)?yīng)的本地類型的數(shù)組的指針。

表B

函數(shù)Java 數(shù)組類型本地類型
GetBooleanArrayElementsjbooleanArrayjboolean
GetByteArrayElementsjbyteArrayjbyte
GetCharArrayElementsjcharArrayjchar
GetShortArrayElementsjshortArrayjshort
GetIntArrayElementsjintArrayjint
GetLongArrayElementsjlongArrayjlong
GetFloatArrayElementsjfloatArrayjfloat
GetDoubleArrayElementsjdoubleArrayjdouble

JNI數(shù)組存取函數(shù)

當(dāng)你對(duì)數(shù)組的存取完成后,要確保調(diào)用相應(yīng)的ReleaseXXXArrayElements函數(shù),參數(shù)是對(duì)應(yīng)Java數(shù)組和GetXXXArrayElements返回的指針。如果必要的話,這個(gè)釋放函數(shù)會(huì)復(fù)制你做的任何變化(這樣它們就反射到j(luò)ava數(shù)組),然后釋放所有相關(guān)的資源。

為了使用java對(duì)象的數(shù)組,你必須使用GetObjectArrayElement函數(shù)和SetObjectArrayElement函數(shù),分別去get,set數(shù)組的元素。GetArrayLength函數(shù)會(huì)返回?cái)?shù)組的長(zhǎng)度。

使用對(duì)象

JNI 提供的另外一個(gè)功能是在本地代碼中使用Java對(duì)象。通過(guò)使用合適的JNI函數(shù),你可以創(chuàng)建Java對(duì)象,get、set 靜態(tài)(static)和實(shí)例(instance)的域,調(diào)用靜態(tài)(static)和實(shí)例(instance)函數(shù)。JNI通過(guò)ID識(shí)別域和方法,一個(gè)域或 方法的ID是任何處理域和方法的函數(shù)的必須參數(shù)。

表C列出了用以得到靜態(tài)(static)和實(shí)例(instance)的域與方法的JNI函數(shù)。每個(gè)函數(shù)接受(作為參數(shù))域或方法的類,它們的名稱,符號(hào)和它們對(duì)應(yīng)返回的jfieldIDjmethodID。

表C

函數(shù)描述
GetFieldID得到一個(gè)實(shí)例的域的ID
GetStaticFieldID得到一個(gè)靜態(tài)的域的ID
GetMethodID得到一個(gè)實(shí)例的方法的ID
GetStaticMethodID得到一個(gè)靜態(tài)方法的ID

※域和方法的函數(shù)

如果你有了一個(gè)類的實(shí)例,它就可以通過(guò)方法GetObjectClass得到,或者如果你沒有這個(gè)類的實(shí)例,可以通過(guò)FindClass得到。符號(hào)是從域的類型或者方法的參數(shù),返回值得到字符串,如表D所示。

表D

Java 類型符號(hào)
booleanZ
byteB
charC
shortS
intI
longL
floatF
doubleD
voidV
objects對(duì)象Lfully-qualified-class-name;L類名
Arrays數(shù)組[array-type [數(shù)組類型
methods方法(argument-types)return-type(參數(shù)類型)返回類型

※確定域和方法的符號(hào)


下面我們來(lái)看看,如果通過(guò)使用數(shù)組和對(duì)象,從C++中的獲取到Java中的DiskInfo 類對(duì)象,并返回一個(gè)DiskInfo數(shù)組:
//返回一個(gè)結(jié)構(gòu)數(shù)組,返回一個(gè)硬盤信息的結(jié)構(gòu)數(shù)組
JNIEXPORT jobjectArray JNICALL Java_com_sundy_jnidemo_ChangeMethodFromJni_getStructArray
(JNIEnv 
*env, jobject _obj)
{
    
//申明一個(gè)object數(shù)組 
    jobjectArray args = 0;
    
    
//數(shù)組大小
    jsize        len = 5;

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

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

    
/**//* 下面為獲取到Java中對(duì)應(yīng)的實(shí)例類中的變量*/

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

    
//給每一個(gè)實(shí)例的變量付值,并且將實(shí)例作為一個(gè)object,添加到objcet數(shù)組中
    for(int  i=0; i < len; i++ )
    
{
        
//給每一個(gè)實(shí)例的變量付值
        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數(shù)組中
        (env)->SetObjectArrayElement(args, i, _obj);
    }

    
//返回object數(shù)組
    return args;

 }


全部的C/C++方法實(shí)現(xiàn)代碼如下:
/**//*
*
* 一縷陽(yáng)光(sundy)版權(quán)所有,保留所有權(quán)利。
*/

/**//**

*  TODO Jni 中一個(gè)從Java到C/C++參數(shù)傳遞測(cè)試類
*
*  @author 劉正偉(sundy)
*  @see 
http://www./sundy
*  @see mailto:sundy26@126.com
*  @version 1.0
*  @since 2005-4-30

*  修改記錄:
*  
*  日期              修改人                 描述
*  ----------------------------------------------------------------------------------------------
*
*
*
*/

// JniManage.cpp : 定義 DLL 應(yīng)用程序的入口點(diǎn)。
//
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" //通過(guò)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類型轉(zhuǎn)換成windows類型
char* jstringToWindows( JNIEnv *env, jstring jstr );
//將windows類型轉(zhuǎn)換成jstring類型
jstring WindowsTojstring( JNIEnv* env, char* str );

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

//輸入常用的數(shù)值類型 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 );
}


//調(diào)用一個(gè)靜態(tài)方法,只有一個(gè)簡(jiǎn)單類型輸出
JNIEXPORT jint JNICALL Java_com_sundy_jnidemo_ChangeMethodFromJni_add
(JNIEnv 
*env, jobject, jint a, jint b)
{
    
int rtn = (int)(a + b);
    
return (jint)rtn;
}


/**/////輸入一個(gè)數(shù)組,這里輸入的是一個(gè)Boolean類型的數(shù)組
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 );
}


/**/////返回一個(gè)字符串?dāng)?shù)組
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;
}


//返回一個(gè)結(jié)構(gòu),這里返回一個(gè)硬盤信息的簡(jiǎn)單結(jié)構(gòu)類型
JNIEXPORT jobject JNICALL Java_com_sundy_jnidemo_ChangeMethodFromJni_getStruct
(JNIEnv 
*env, jobject obj)
{
    
/**//* 下面為獲取到Java中對(duì)應(yīng)的實(shí)例類中的變量*/

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

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


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


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

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

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

    
/**//* 下面為獲取到Java中對(duì)應(yīng)的實(shí)例類中的變量*/

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

    
//給每一個(gè)實(shí)例的變量付值,并且將實(shí)例作為一個(gè)object,添加到objcet數(shù)組中
    for(int  i=0; i < len; i++ )
    
{
        
//給每一個(gè)實(shí)例的變量付值
        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數(shù)組中
        (env)->SetObjectArrayElement(args, i, _obj);
    }

    
//返回object數(shù)組
    return args;

 }


//將jstring類型轉(zhuǎn)換成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類型轉(zhuǎn)換成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 測(cè)試native代碼
這沒有什么多說(shuō)的,看代碼吧
//主測(cè)試程序
    public static void main(String[] args) {
        ChangeMethodFromJni changeJni 
= new ChangeMethodFromJni();

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

        
//調(diào)用一個(gè)靜態(tài)方法
        System.out.println("------------------調(diào)用一個(gè)靜態(tài)方法-----------");
        
int ret = changeJni.add(1220);
        System.
out.println("The result is: " + String.valueOf(ret));

        
//輸入一個(gè)數(shù)組
        System.out.println("------------------輸入一個(gè)數(shù)組-----------");
        boolean[] blList 
= new boolean[] truefalsetrue };
        changeJni.setArray(blList);

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

        System.
out.println();

        System.
out.println("------------------返回一個(gè)結(jié)構(gòu)-----------");

        
//返回一個(gè)結(jié)構(gòu)
        DiskInfo disk = changeJni.getStruct();
        System.
out.println("name:" + disk.name);
        System.
out.println("Serial:" + disk.serial);

        
//返回一個(gè)結(jié)構(gòu)數(shù)組

        System.
out.println("------------------返回一個(gè)結(jié)構(gòu)數(shù)組 -----------");
        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);
        }


    }

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多