日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JNI中参数的传递与操作

發布時間:2025/1/21 编程问答 87 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JNI中参数的传递与操作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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;

//序列號
publicint 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類型本地類型描述
booleanjbooleanC/C++8位整型
bytejbyteC/C++帶符號的8位整型
charjcharC/C++無符號的16位整型
shortjshortC/C++帶符號的16位整型
intjintC/C++帶符號的32位整型
longjlongC/C++帶符號的64位整型e
floatjfloatC/C++32位浮點型
doublejdoubleC/C++64位浮點型
Objectjobject任何Java對象,或者沒有對應java類型的對象
ClassjclassClass對象
Stringjstring字符串對象
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數組類型本地類型
GetBooleanArrayElementsjbooleanArrayjboolean
GetByteArrayElementsjbyteArrayjbyte
GetCharArrayElementsjcharArrayjchar
GetShortArrayElementsjshortArrayjshort
GetIntArrayElementsjintArrayjint
GetLongArrayElementsjlongArrayjlong
GetFloatArrayElementsjfloatArrayjfloat
GetDoubleArrayElementsjdoubleArrayjdouble

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 類型符號
booleanZ
byteB
charC
shortS
intI
longL
floatF
doubleD
voidV
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)
{
constchar* 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代碼
這沒有什么多說的,看代碼吧
//主測試程序
publicstaticvoid 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);
? ? ? ?}


? ?}


轉載于:https://blog.51cto.com/laokaddk/1343401

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的JNI中参数的传递与操作的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。