如何使用JNI的一些基本方法和過程在網(wǎng)上多如牛毛,如果你對(duì)Jni不甚了解,不知道Jni是做什么的,如何建立一個(gè)基本的jni程序,或許可以參考下面下面這些文章: 利用VC++6.0實(shí)現(xiàn)JNI的最簡單的例子 JNI入門教程之HelloWorld篇 SUN JNI Tutorial 謝謝大家的回復(fù),有人說類型不對(duì),己修正。類型請(qǐng)參照:
http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html 這些資料的例子中,大多數(shù)只是輸入一些簡單的參數(shù),獲取沒有參數(shù)。而在實(shí)際的使用過程中,往往需要對(duì)參數(shù)進(jìn)行處理轉(zhuǎn)換。才可以被C/C++程序識(shí)別。比如我們?cè)贑++中有一個(gè)結(jié)構(gòu)(Struct)DiskInfo ,需要傳遞一個(gè)類似于DiskInfo *pDiskInfo的參數(shù),類似于在C++這樣參數(shù)如何傳遞到Java中呢?下面我們就來討論C++到Java中方法的一些常見參數(shù)的轉(zhuǎn)換:
定義Native Java類:
如果你習(xí)慣了使用JNI,你就不會(huì)覺得它難了。既然本地方法是由其他語言實(shí)現(xiàn)的,它們?cè)贘ava中沒有函數(shù)體。但是,所有本地代碼必須用本地關(guān)鍵詞聲明,成為Java類的成員。假設(shè)我們?cè)贑++中有這么一個(gè)結(jié)構(gòu),它用來描述硬盤信息:
//
硬盤信息
struct
{
char
name[
256
];
int
serial;
}
DiskInfo;
那么我們需要在Java中定義一個(gè)類來與之匹配,聲明可以寫成這樣:
class
DiskInfo
{
//
名字
public
String name;

//
序列號(hào)
public
int
serial;
}
在這個(gè)類中,申明一些Native的本地方法,來測試方法參數(shù)的傳遞,分別定義了一些函數(shù),用來傳遞結(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類之后,接下來就要寫本地代碼。本地方法符號(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)是用來調(diào)用JNI函數(shù)的。第二個(gè)參數(shù)jclass的意義,要看方法是不是靜態(tài)的(static)或者實(shí)例(Instance)的。前者,jclass代表一個(gè)類對(duì)象的引用,而后者是被調(diào)用的方法所屬對(duì)象的引用。
返回值和參數(shù)類型根據(jù)等價(jià)約定映射到本地C/C++類型,如表JNI類型映射所示。有些類型,在本地代碼中可直接使用,而其他類型只有通過JNI調(diào)用操作。
表A
Java
類型
|
本地類型
|
描述
|
boolean |
jboolean |
C/C++8位整型 |
byte |
jbyte |
C/C++帶符號(hào)的8位整型 |
char |
jchar |
C/C++無符號(hào)的16位整型 |
short |
jshort |
C/C++帶符號(hào)的16位整型 |
int |
jint |
C/C++帶符號(hào)的32位整型 |
long |
jlong |
C/C++帶符號(hào)的64位整型e |
float |
jfloat |
C/C++32位浮點(diǎn)型 |
double |
jdouble |
C/C++64位浮點(diǎn)型 |
Object |
jobject |
任何Java對(duì)象,或者沒有對(duì)應(yīng)java類型的對(duì)象 |
Class |
jclass |
Class對(duì)象 |
String |
jstring |
字符串對(duì)象 |
Object[] |
jobjectArray |
任何對(duì)象的數(shù)組 |
boolean[] |
jbooleanArray |
布爾型數(shù)組 |
byte[] |
jbyteArray |
比特型數(shù)組 |
char[] |
jcharArray |
字符型數(shù)組 |
short[] |
jshortArray |
短整型數(shù)組 |
int[] |
jintArray |
整型數(shù)組 |
long[] |
jlongArray |
長整型數(shù)組 |
float[] |
jfloatArray |
浮點(diǎn)型數(shù)組 |
double[] |
jdoubleArray |
雙浮點(diǎn)型數(shù)組 |
※ JNI類型映射
使用數(shù)組:
JNI通過JNIEnv提供的操作Java數(shù)組的功能。它提供了兩個(gè)函數(shù):一個(gè)是操作java的簡單型數(shù)組的,另一個(gè)是操作對(duì)象類型數(shù)組的。
因?yàn)樗俣鹊脑颍唵晤愋偷臄?shù)組作為指向本地類型的指針暴露給本地代碼。因此,它們能作為常規(guī)的數(shù)組存取。這個(gè)指針是指向?qū)嶋H的Java數(shù)組或者Java數(shù)組的拷貝的指針。另外,數(shù)組的布置保證匹配本地類型。
為了存取Java簡單類型的數(shù)組,你就要要使用GetXXXArrayElements函數(shù)(見表B),XXX代表了數(shù)組的類型。這個(gè)函數(shù)把Java數(shù)組看成參數(shù),返回一個(gè)指向?qū)?yīng)的本地類型的數(shù)組的指針。
表B
函數(shù)
|
Java
數(shù)組類型
|
本地類型
|
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數(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ù)組的長度。
使用對(duì)象
JNI提供的另外一個(gè)功能是在本地代碼中使用Java對(duì)象。通過使用合適的JNI函數(shù),你可以創(chuàng)建Java對(duì)象,get、set 靜態(tài)(static)和實(shí)例(instance)的域,調(diào)用靜態(tài)(static)和實(shí)例(instance)函數(shù)。JNI通過ID識(shí)別域和方法,一個(gè)域或方法的ID是任何處理域和方法的函數(shù)的必須參數(shù)。
表C列出了用以得到靜態(tài)(static)和實(shí)例(instance)的域與方法的JNI函數(shù)。每個(gè)函數(shù)接受(作為參數(shù))域或方法的類,它們的名稱,符號(hào)和它們對(duì)應(yīng)返回的jfieldID或jmethodID。
表C
函數(shù)
|
描述 |
GetFieldID |
得到一個(gè)實(shí)例的域的ID |
GetStaticFieldID |
得到一個(gè)靜態(tài)的域的ID |
GetMethodID |
得到一個(gè)實(shí)例的方法的ID |
GetStaticMethodID |
得到一個(gè)靜態(tài)方法的ID |
※域和方法的函數(shù)
如果你有了一個(gè)類的實(shí)例,它就可以通過方法GetObjectClass得到,或者如果你沒有這個(gè)類的實(shí)例,可以通過FindClass得到。符號(hào)是從域的類型或者方法的參數(shù),返回值得到字符串,如表D所示。
表D
Java
類型
|
符號(hào)
|
boolean |
Z |
byte |
B |
char |
C |
short |
S |
int |
I |
long |
J |
float |
F |
double |
D |
void |
V |
objects對(duì)象 |
Lfully-qualified-class-name;L類名 |
Arrays數(shù)組 |
[array-type [數(shù)組類型 |
methods方法 |
(argument-types)return-type(參數(shù)類型)返回類型 |
※確定域和方法的符號(hào)
下面我們來看看,如果通過使用數(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)代碼如下:  /**//*
*
* 一縷陽光(sundy)版權(quán)所有,保留所有權(quán)利。
*/
 /**//**
*
* TODO Jni 中一個(gè)從Java到C/C++參數(shù)傳遞測試類
*
* @author 劉正偉(sundy)
* @see http://www.cnweblog.com/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" //通過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è)簡單類型輸出
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é)構(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 測試native代碼這沒有什么多說的,看代碼吧 //主測試程序
 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!", 100, true);

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

//輸入一個(gè)數(shù)組
System.out.println("------------------輸入一個(gè)數(shù)組-----------");
 boolean[] blList = new boolean[] { true, false, true };
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);
}

}注:本程序在VS2003,eclipse (jse5.0) winxp sp2編譯通過 ————————————————————————————————————————————
|
|
|
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
24 | 25 | 26 | 27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 |
|
導(dǎo)航
統(tǒng)計(jì)
- 隨筆: 115
- 文章: 1
- 評(píng)論: 86
- 引用: 0
常用鏈接
留言簿(5)
隨筆檔案(115)
網(wǎng)址
搜索
積分與排名
最新評(píng)論

閱讀排行榜
評(píng)論排行榜
|
|