`

java与c/c++之间的数据交互

 
阅读更多

最近作一个tiemsten数据库的项目,用到了jni技术。在这个项目中,我们用java来写界面和业务逻辑,用c语言写数据库odbc访问。单 纯的odbc其实没有什么难的,但是在java和c之间进行数据传递是比较麻烦的事情。两者之间数据的传递有这样几种情况:java和c之间基本数据类型 的交互,java向c传递对象类型,c向java返回对象类型,c调用java类。下面就这样几种情况分类说明。

1、java 向c传递基本数据类型

对于基本数据类型,java和c是相互对应的,所以可以直接使用。它们的对应关系为;

------------------------------------------------------------------------

Java类型      本地类型   字节(bit)

-------------------------------------------------------------------------
  
  boolean   jboolean   8, unsigned
  byte    jbyte     8
  char    jchar    16, unsigned
  short    jshort    16
  int     jint     32
  long    jlong    64
  float    jfloat    32
  double   jdouble   64
  void    void     n/a

------------------------------------------------------------------------

2.java向c传递对象类型

对于java传递进来的java对象模型,c要加载java类的原型,根据创建相应的c对象,获取java对象的方法的id,然后调用java对象 的方法。举例说明:比如有个java类customer对象作为jni参数传递到c程序,customer有方法String getName()。

JNIEXPORT jobject JNICALL Java_com_oracle_estt_sc_db_impl_SCQueryODBC__1getCustomer
(JNIEnv *env, jobject,  jobject customer){

jmethodID methodId; 
 //获得customer对象的句柄
    jclass cls_objClass=env->GetObjectClass(customer); 
 //获得customer对象中特定方法getName的id 
 methodId=env->GetMethodID(cls_objClass,"getName","()Ljava/lang/String;");
 //调用customer对象的特定方法getName
 jstring  js_name=(jstring)env->CallObjectMethod(customer,methodId,NULL);

...

}

3.c向java返回对象类型

在c程序中首先要创建要返回的java对象,得到每个属性的id,然后给每个属性赋值,最后返回。举例说明:同样是customer对象,有name等属性值,需要在c程序中给每个属性赋值后返回。

JNIEXPORT jobject JNICALL Java_com_oracle_estt_sc_db_impl_SCQueryODBC__1getCustomer
(JNIEnv *env, jobject,  jobject customer){

......

//发现java Customer类,如果失败,程序返回
 jclass   clazz = env->FindClass("com/oracle/estt/sc/busi/Customer");  
 if(clazz == 0) 
  return   0;   
 //为新的java类对象obj分配内存   
 jobject   obj = env->AllocObject(clazz);    
 //发现类中的属性,如果失败,程序返回  
 jfieldID   fid_id = env->GetFieldID(clazz,"customerID","I"); 
 if (fid_id  ==  0) 
  return   0;
 jfieldID   fid_name = env->GetFieldID(clazz,"name","Ljava/lang/String;"); 
 if (fid_name  ==  0) 
  return   0;
......

 env->SetIntField(obj, fid_id, 1);
 env->SetObjectField(obj, fid_name, jname);

......

return obj;

}

4.c向java传递一个含有java对象的数组

对于这种情况,先得到数组的大小,接下来取出数组中的对象,取得对象的属性值或者调用对象的方法,将获得值存到本地数组中,然后可以灵活使用这些数 据了。举例说明:java向c传递一个含有多个customer对象的数组,在c中将这个数组的分解出来,存到本地的临时数组中去。

JNIEXPORT void JNICALL Java_com_oracle_estt_sc_db_impl_SCInsertODBC__1insertCustomeRequest___3Lcom_oracle_estt_sc_busi_CustomerRequest_2
(JNIEnv *env, jobject, jobjectArray oa){

...... 

//声明customerrequest对象
 jobject o_customer;

 int i;
 jmethodID methodId; 
 jint size=env->GetArrayLength(oa);

_tmp_bind[0]= (char *)malloc(size*sizeof(int));
 _tmp_bind[1]= (char *)malloc(size*sizeof(char)*( 20 + 1));

...

//将输入数组的数据拷贝到临时数组中去
 for(i=0;i<size;i++){
 //从数组中获得customerrequest对象
    o_request=env->GetObjectArrayElement(oa,i);
 //获得customerrequest对象的句柄
 jclass cls_objClass=env->GetObjectClass(o_request);
 
 //获得customerrequest对象的特定方法getCustomerID的id
 methodId=env->GetMethodID(cls_objClass,"getCustomerID","()I");
 //调用customerrequest对象的特定方法getCustomerID
 int_customerID=env->CallIntMethod(o_request,methodId,NULL); 
 //获得customerrequest对象中特定方法getTelNum的id 
 methodId=env->GetMethodID(cls_objClass,"getTelNum","()Ljava/lang/String;");
 //调用customerrequest对象的特定方法getTelNum
 str_telNum=(jstring)env->CallObjectMethod(o_request,methodId,NULL); 

...

//将用户id拷贝到临时数组
 memcpy(_tmp_bind[0]+i*sizeof(int),&int_customerID,sizeof(int));

 //将电话号码拷贝到临时数组,如果电话号码字符串超长,报错返回
 if(sizeof(char)*strlen(chr_tel)<=sizeof(char)*( 20 + 1)){
 memcpy(_tmp_bind[1]+i*sizeof(char)*( 20+1 ),chr_tel,strlen(chr_tel)+1);
 }else{
 printf("%s too long!\n",chr_tel);
 return;
 }

...

}

...

}

5.c向java返回一个数组

先创建数组,然后加载java对象,给每个java对象的属性赋值,添加到数组中,最后返回数组。如下例:

JNIEXPORT jobjectArray JNICALL Java_com_oracle_estt_sc_db_impl_SCQueryODBC__1getCustomerRequest
(JNIEnv *env, jobject, jint customerid){

......

 //声明存放查询结果的objectarray
 jobjectArray jo_array = env->NewObjectArray(MAX_LINE,env->FindClass("com/oracle/estt/sc/busi/CustomerRequest"), 0);  jobject obj;
 //发现java Customerrequest类,如果失败,程序返回
 jclass   clazz = env->FindClass("com/oracle/estt/sc/busi/CustomerRequest");  
 if(clazz == 0) 
  return   0;

 while ((rc = SQLFetch(hstmt)) == SQL_SUCCESS ||rc == SQL_SUCCESS_WITH_INFO) {

 obj = env->AllocObject(clazz);

jfieldID   fid_customerID = env->GetFieldID(clazz,"customerID","I"); 
  if (fid_customerID  ==  0) 
   return   0;

jfieldID   fid_priority = env->GetFieldID(clazz,"priority","I"); 
  if (fid_priority  ==  0) 
   return   0;

...

env->SetIntField(obj, fid_customerID, col_customerID);

env->SetIntField(obj, fid_priority, col_priority);

...

//将对象obj添加到object array中
  if(j<MAX_LINE){
   env->SetObjectArrayElement(jo_array, j, obj);
  }else{
   break;
  }

}

return jo_array;

}

6.jstring向char* 的转换

jstring不能直接在c程序中使用,需要转换成char*。重要的一点是,在使用完char*之后,一定要记得将其释放,以免发生内存泄漏。如下例:

JNIEXPORT jobjectArray JNICALL Java_com_oracle_estt_sc_db_impl_SCQueryODBC__1getCustomerRequestByCondition
(JNIEnv *env, jobject, jstring condition, jint customerid){

//将jstring转换为cha*
 char* str_condition=(char*) env->GetStringUTFChars(condition,JNI_FALSE);

......

//释放变量
 env->ReleaseStringUTFChars(condition,str_condition);

......

}

7.char*转换成jstring

这个转换就比较麻烦了,但是在数据库操作时会用到。比如,从数据库查询得到的是char*,但是给对象属性赋值的时候需要用jstring,这是需要用到这种转换。具体如下例:

char* col_timestamp=.....;

//加载string类
 jclass strClass = env->FindClass("Ljava/lang/String;");
 //获得方法id
 jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");

//将字符串转换为jstring  
  bytes_time = env->NewByteArray(strlen(col_timestamp));
  env->SetByteArrayRegion(bytes_time, 0, strlen(col_timestamp), (jbyte*)col_timestamp);
  jstring js_time = env->NewStringUTF("utf-8");

js_time=(jstring)env->NewObject(strClass, ctorID, bytes_time, js_time)

8.java类的原型获取方法

在c中创建java对象和调用java对象方法时需要用到java类的原型,特别是其方法签名。具体办法是:到java类所在的目录下,键入名命令:

>javap -s -p 包路径.java类名

以上几点是我这两天写jni程序的一点总结,写出来与大家分享,欢迎批评指导。

推荐资料:

Java Native Interface Specification.http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/jniTOC.html

分享到:
评论

相关推荐

    java与c++交互(JNI学习笔记)

    1.C++与java交互基本介绍 2.C++获取java属性值、设置java属性值 3.C++创建java对象 4.C++中数据类型间的转换

    Cocos2d-x与Android交互(c++与java互调),与IOS交互(c++与objective c混编)

    Cocos2d-x与Android交互(c++与java互调),与IOS交互(c++与objective c混编) 具体的代码请下载这个文件,里面有更详细的jni使用方法,包括传递基本数据类型,返回基本数据类型的值,及类型的转换。

    C++ 与 Java 混合编程示例源代码

    底层的指令或核心算法,会使用C/C++处理,涉及数据处理的时候,为了安全和快速开发,会使用Javascript或Python等脚本语言实现数据分析处理。因此,开发者应该学习或掌握语言混合编程。 C++和Java是主流的两种编程...

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    / 301 11.3.2 公共子表达式消除 / 305 11.3.3 数组边界检查消除 / 307 11.3.4 方法内联 / 307 11.3.5 逃逸分析 / 309 11.4 Java与C/C++的编译器对比 / 311 11.5 本章小结 / 313 第五部分 高效并发 第12章 ...

    Android Camera框架

    另一个是service 进程,属于服务端,是native c/c++代码,主要负责和linux kernel中的camera driver交互,搜集linux kernel中camera driver传上来的数据,并交给显示系统(surface)显示。client进程与service进程通过...

    基于java的企业级应用开发:JSON数据交互.ppt

    它是基于JavaScript的一个子集,使用了C、C++、C#、Java、JavaScript、Perl、Python等其他语言的约定,采用完全独立于编程语言的文本格式来存储和表示数据。 JSON与XML非常相似,都是用来存储数据的,并且都是基于纯...

    深入理解React Native原生模块与JS模块通信的几种方式

    每种语言都有自己的设计理念、语法、运行环境,这也导致了不同语言间相互交流通信时必须要有中介来翻译,如JAVA与C/C++通过JNI来交流、OC与C/C++需要在.mm文件混编、而JAVA/OC与Lua通信时需要通过C/C++语言来做中介...

    JAVA上百实例源码以及开源项目源代码

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    NDK中JAVA和C互相调用

    JAVA调用C, C调用JAVA创建一个按钮 这个按钮点击后,又调用一个C函数 改编自NDK例子

    netty 在java中的字节码转换

    netty通信时经常和底层数据交互,C语言和java的数据类型和范围不同,通信时需要转化或兼容,附件为字节码、进制常用的转换类。

    JAVA上百实例源码以及开源项目

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    精通D3.js:交互式数据可视化高级编程.azw3

    《精通D3.js:交互式数据可视化高级编程》以当前流行的...《精通D3.js:交互式数据可视化高级编程》适合有一定计算机基础的读者,需要熟悉C、C++、Java、JavaScript等至少一门编程语言,能够理解基础的数据结构和算法。

    cmake跨平台sdk开发和Jni 接口设计及应用

    1:cmake 跨平台sdk 开发快速入门...2:java的jni 技术,java 和c/c++ 的数据交互(包括基本类型和数组类型和类的相互传递)和相互调用 3:学会写java测试demo, 以及学会写安卓测试demo,测试自己所写的sdk 能否调用正常

    java开源包4

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包11

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包101

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包6

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包9

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

Global site tag (gtag.js) - Google Analytics