科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件讲解如何在C/C++中调用Java的方法 (4)

讲解如何在C/C++中调用Java的方法 (4)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

讲解如何在C/C++中调用Java的方法 (4)

作者:ChinaITLab 来源:ChinaITLab 2007年11月8日

关键字: java 调用 C++ Linux

  • 评论
  • 分享微博
  • 分享邮件

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;
  }
查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章