3.读取和设置属性值
有了属性的定义要访问属性值就很容易了。有几个方法用来读取和设置类的属性,它们是:GetField、SetField、GetStaticField、SetStaticField。比如读取Demo类的msg属性就可以用GetObjectField,而访问COUNT用GetStaticIntField,相关代码如下:
jfieldID field =
(*env)->GetFieldID
(env,obj,"msg"," Ljava/lang/String;");
jstring msg =
(*env)-> GetObjectField(env, cls, field);
//msg就是对应Demo的msg
jfieldID field2 =
(*env)->GetStaticFieldID(env,obj,"COUNT","I");
jint count =
(*env)->GetStaticIntField(env,cls,field2); |
访问构造函数
很多人刚刚接触JNI的时候往往会在这一节遇到问题,查遍了整个jni.h看到这样一个函数NewObject,它应该是可以用来访问类的构造函数。但是该函数需要提供构造函数的方法定义,其类型是jmethodID。从前面的内容我们知道要获取方法的定义首先要知道方法的名称,但是构造函数的名称怎么来填写呢?其实访问构造函数与访问一个普通的类方法大体上是一样的,惟一不同的只是方法名称不同及方法调用时不同而已。访问类的构造函数时方法名必须填写“”。下面的代码演示如何构造一个Demo类的实例:
jclass cls =
(*env)->FindClass(env, "jni/test/Demo");
/**
首先通过类的名称获取类的定义,
相当于Java中的Class.forName方法
*/
if (cls == 0)
<error handler>
jmethodID mid = (*env)->GetMethodID
(env,cls,"<init>","(Ljava/lang/String;)V ");
if(mid == 0)
<error handler>
jobject demo = jenv->NewObject(cls,mid,0);
/**
访问构造函数必须
使用NewObject的函数
来调用前面获取的构造函数的定义
上面的代码我们构造了
一个Demo的实例并传一个空串null
*/ |
数组处理
创建一个新数组
要创建一个数组,我们首先应该知道数组元素的类型及数组长度。JNI定义了一批数组的类型jArray及数组操作的函数NewArray,其中就是数组中元素的类型。例如,要创建一个大小为10并且每个位置值分别为1-10的整数数组,编写代码如下:
int i = 1;
jintArray array;
//定义数组对象
(*env)-> NewIntArray(env, 10);
for(; i<= 10; i++)
(*env)->SetIntArrayRegion
(env, array, i-1, 1, &i); |
访问数组中的数据
访问数组首先应该知道数组的长度及元素的类型。现在我们把创建的数组中的每个元素值打印出来,代码如下:
int i;
/* 获取数组对象的元素个数 */
int len =
(*env)->GetArrayLength(env, array);
/* 获取数组中的所有元素 */
jint* elems =
(*env)-> GetIntArrayElements
(env, array, 0);
for(i=0; i< len; i++)
printf("ELEMENT %d IS %d\n",
i, elems[i]); |
中文处理
中文字符的处理往往是让人比较头疼的事情,特别是使用Java语言开发的软件,在JNI这个问题更加突出。由于Java中所有的字符都是Unicode编码,但是在本地方法中,例如用VC编写的程序,如果没有特殊的定义一般都没有使用Unicode的编码方式。为了让本地方法能够访问Java中定义的中文字符及Java访问本地方法产生的中文字符串,我定义了两个方法用来做相互转换。
方法一,将Java中文字符串转为本地字符串
/**
第一个参数是虚拟机的环境指针
第二个参数为待转换的Java字符串定义
第三个参数是本地存储转换后字符串的内存块
第三个参数是内存块的大小
*/
int JStringToChar
(JNIEnv *env, jstring str,
LPTSTR desc, int desc_len)
{
int len = 0;
if(desc==NULL||str==NULL)
return -1;
//在VC中wchar_t是用来
存储宽字节字符(UNICODE)的数据类型
wchar_t *w_buffer = new wchar_t[1024];
ZeroMemory(w_buffer,1024*sizeof(wchar_t));
//使用GetStringChars
而不是GetStringUTFChars
wcscpy(w_buffer,env->
GetStringChars(str,0));
env->ReleaseStringChars
(str,w_buffer);
ZeroMemory(desc,desc_len);
//调用字符编码转换函数(Win32 API)
将UNICODE转为ASCII编码格式字符串
len = WideCharToMultiByte
(CP_ACP,0,w_buffer,1024,desc,
desc_len,NULL,NULL);
//len = wcslen(w_buffer);
if(len>0 && len<desc_len)
desc[len]=0;
delete[] w_buffer;
return strlen(desc);
} |
方法二,将C的字符串转为Java能识别的Unicode字符串
jstring NewJString
(JNIEnv* env,LPCTSTR str)
{
if(!env || !str)
return 0;
int slen = strlen(str);
jchar* buffer = new jchar[slen];
int len = MultiByteToWideChar
(CP_ACP,0,str,strlen(str),buffer,slen);
if(len>0 && len < slen)
buffer[len]=0;
jstring js =
env->NewString(buffer,len);
delete [] buffer;
return js;
} | |