Java JNI由浅入深(包括:Java和C++互传ArrayList泛型对象参数)

2010-11-25 09:57 1694人阅读 评论(1) 收藏 举报

我们知道Java是一个运行在虚拟机里面的高级的编程语言,如果要调用系统的动态链接库的话,就要先声明native修饰的方法(类似接口里面的方法),再由C/C++程序来实现(类似实现接口里的方法)。这样Java调用这些native方法就相当于调用了C/C++里面实现了的方法。通常我们把这种机制叫做JNI(Java NativeInterfac),即Java 本地编程接口

Android也同理,要学会在Android上进行NDK开发,首先我们到打好java JNI的基础。现在我们暂时把Android开发丢到一边先,试试在Java之下编译一个C动态链接库,再用Java程序调用。

1)先来个最简单的打印HelloWorld例子:

Java代码(HelloJni.java):

[java] view plaincopy
  1. import java.util.*;
  2. public class HelloJni{
  3. static{
  4. System.loadLibrary("hello");
  5. }
  6. public native static void sayHello();
  7. public static void main(String [] args)
  8. {
  9. HelloJni.sayHello();
  10. }
  11. }

生成头文件(HelloJni.h):

先javac HelloJni.java编译你的Java源码,再javah–jni HelloJni生成所需的头文件

头文件内容是这样的:

[java] view plaincopy
  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. /* Header for class HelloJni */
  4. #ifndef _Included_HelloJni
  5. #define _Included_HelloJni
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. JNIEXPORT void JNICALL Java_HelloJni_sayHello (JNIEnv *, jclass);
  10. #ifdef __cplusplus
  11. }
  12. #endif
  13. #endif

实现头文件声明的方法(HelloJni.cpp)

[c-sharp] view plaincopy
  1. #include "HelloJni.h"
  2. JNIEXPORT void JNICALL Java_HelloJni_sayHello(JNIEnv *env, jclass cls)
  3. {
  4. printf("HelloWorld");
  5. }

编译命令: g++ -I$JAVA_HOME/include-I$JAVA_HOME/include/linux HelloJni.cpp -shared -o libhello.so

命令参数解析:-I 是指引入java虚拟机的库的路径,-shared 是指编译成动态链接库(共享库) –o 输出文件名(注意,在Linux平台下的动态链接库有一个命名格式:“lib+库名+.so”在java代码里面loadLibrary的时候不要加lib前缀和.so后缀)

由于我这里把这个动态链接库编译放在当前目录下,所以还要设置环境变量LD_LIBRARY_PATH=该so动态链接库所在的目录,才能正常运行

#############################+++华丽的分割线+++###########################

2)好了,可以打印HelloWorld出来后,我们再深入一点点,传入一个int的数,在C/C++代码里面加1后返回。

Java代码(HelloJni.java):

[java] view plaincopy
  1. public class HelloJni{
  2. static{
  3. System.loadLibrary("hello");
  4. }
  5. public static native void sayHello();
  6. public native int getInt();
  7. public native void setInt(int i);
  8. public static void main(String args[]){
  9. //      HelloJni.sayHello();
  10. HelloJni hello = new HelloJni();
  11. hello.setInt(2);
  12. System.out.println(hello.getInt());
  13. }
  14. }

生成头文件(HelloJni.h):

[c-sharp] view plaincopy
  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. /* Header for class HelloJni */
  4. #ifndef _Included_HelloJni
  5. #define _Included_HelloJni
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. JNIEXPORT void JNICALL Java_HelloJni_sayHello (JNIEnv *, jclass);
  10. JNIEXPORT jint JNICALL Java_HelloJni_getInt (JNIEnv *, jobject);
  11. JNIEXPORT void JNICALL Java_HelloJni_setInt (JNIEnv *, jobject, jint);
  12. #ifdef __cplusplus
  13. }
  14. #endif
  15. #endif

实现头文件声明的方法(HelloJni.cpp)

[java] view plaincopy
  1. #include "HelloJni.h"
  2. int i=1;
  3. JNIEXPORT void JNICALL Java_HelloJni_sayHello
  4. (JNIEnv *env, jclass cls){
  5. printf("HelloWorld/n");
  6. }
  7. JNIEXPORT jint JNICALL Java_HelloJni_getInt
  8. (JNIEnv *env, jobject thiz){
  9. return i;
  10. }
  11. JNIEXPORT void JNICALL Java_HelloJni_setInt
  12. (JNIEnv *env, jobject thiz,jint ji){
  13. i = ji+1;
  14. }

运行结果:打印2

3)只是传入简单的数据类型不爽,这次让C/C++生成个Java对象返回

Java代码:pojo实体类(User.java)

[c-sharp] view plaincopy
  1. public class User{
  2. private long id;
  3. private String userName;
  4. private boolean isMan;
  5. private int age;
  6. public User(){}
  7. public User(long id, String userName, boolean isMan, int age) {
  8. super();
  9. this.id = id;
  10. this.userName = userName;
  11. this.isMan = isMan;
  12. this.age = age;
  13. }
  14. public long getId() {
  15. return id;
  16. }
  17. public void setId(long id) {
  18. this.id = id;
  19. }
  20. public String getUserName() {
  21. return userName;
  22. }
  23. public void setUserName(String userName) {
  24. this.userName = userName;
  25. }
  26. public boolean isMan() {
  27. return isMan;
  28. }
  29. public void setMan(boolean isMan) {
  30. this.isMan = isMan;
  31. }
  32. public int getAge() {
  33. return age;
  34. }
  35. public void setAge(int age) {
  36. this.age = age;
  37. }
  38. }

Java代码(HelloJni.java):

[java] view plaincopy
  1. public class HelloJni{
  2. static{
  3. System.loadLibrary("userbean");
  4. }
  5. public static native void sayHello();
  6. public native int getInt();
  7. public native void setInt(int i);
  8. public native void setUser(String userName);
  9. public native User getUser();
  10. public static void main(String args[]){
  11. //      HelloJni.sayHello();
  12. HelloJni hello = new HelloJni();
  13. //      hello.setInt(2);
  14. //      System.out.println(hello.getInt());
  15. hello.setUser("LiangYaotian");
  16. User user = hello.getUser();
  17. System.out.println("user from c/c++");
  18. System.out.println("name:"+user.getUserName());
  19. System.out.println("isMan?:"+user.isMan());
  20. System.out.println("age:"+user.getAge());
  21. }
  22. }

生成头文件(HelloJni.h):

[c-sharp] view plaincopy
  1. #include <jni.h>
  2. /* Header for class HelloJni */
  3. #ifndef _Included_HelloJni
  4. #define _Included_HelloJni
  5. #ifdef __cplusplus
  6. extern "C" {
  7. #endif
  8. JNIEXPORT void JNICALL Java_HelloJni_sayHello (JNIEnv *, jclass);
  9. JNIEXPORT jint JNICALL Java_HelloJni_getInt (JNIEnv *, jobject);
  10. JNIEXPORT void JNICALL Java_HelloJni_setInt (JNIEnv *, jobject, jint);
  11. JNIEXPORT void JNICALL Java_HelloJni_setUser (JNIEnv *, jobject, jstring);
  12. JNIEXPORT jobject JNICALL Java_HelloJni_getUser  (JNIEnv *, jobject);
  13. #ifdef __cplusplus
  14. }
  15. #endif
  16. #endif

实现头文件声明的方法(HelloJni.cpp)

[c-sharp] view plaincopy
  1. #include <iostream>
  2. #include <stdio.h>
  3. using namespace std;
  4. int i=1;
  5. jobject user;
  6. JNIEXPORT void JNICALL Java_HelloJni_sayHello
  7. (JNIEnv *env, jclass cls){
  8. printf("HelloWorld/n");
  9. }
  10. JNIEXPORT jint JNICALL Java_HelloJni_getInt
  11. (JNIEnv *env, jobject thiz){
  12. return i;
  13. }
  14. JNIEXPORT void JNICALL Java_HelloJni_setInt
  15. (JNIEnv *env, jobject thiz,jint ji){
  16. i = ji+1;
  17. }
  18. JNIEXPORT void JNICALL Java_HelloJni_setUser
  19. (JNIEnv *env, jobject thiz, jstring name){
  20. jclass userClass = env->FindClass("User");
  21. jmethodID userMethod = env->GetMethodID(userClass,"<init>","()V");
  22. jfieldID mId = env->GetFieldID(userClass,"id","J");
  23. jfieldID mUserName = env->GetFieldID(userClass,"userName","Ljava/lang/String;");
  24. jfieldID mIsMan = env->GetFieldID(userClass,"isMan","Z");
  25. jfieldID mAge = env->GetFieldID(userClass,"age","I");
  26. jobject userObject = env->NewObject(userClass,userMethod);
  27. env->SetObjectField(userObject,mUserName,name);
  28. env->SetLongField(userObject,mId,1001);
  29. env->SetBooleanField(userObject,mIsMan,1);
  30. env->SetIntField(userObject,mAge,21);
  31. user = userObject;
  32. }

4)有些同学可能会说:“返回个Java对象算什么啊,C/C++和Java之间互传复杂对象才好玩呢!”正所谓“不怕做不到,就怕想不到”,我们接着重构一下上面那个例子!

这次我们传包含有User对象的List到C/C++程序里面

Java代码(User.java)

同上。

Java代码(HelloJni.java)

[java] view plaincopy
  1. import java.util.*;
  2. public class HelloJni{
  3. static{
  4. System.loadLibrary("userbean");
  5. }
  6. public native int get();
  7. public native void set(int i);
  8. public native void setUser(String userName);
  9. public native User getUser();
  10. public native void setUserList(ArrayList<User> userList);
  11. public native ArrayList<User> getUserList();
  12. public static void main(String [] args)
  13. {
  14. HelloJni hello = new HelloJni();
  15. //      hello.set(2);
  16. //      System.out.println(hello.get());
  17. /*
  18. hello.setUser("LiangYaotian");
  19. User user = hello.getUser();
  20. System.out.println("user from c/c++");
  21. System.out.println("name:"+user.getUserName());
  22. System.out.println("isMan?:"+user.isMan());
  23. System.out.println("age:"+user.getAge());
  24. */
  25. ArrayList<User> userList = new ArrayList<User>();
  26. for(int i=0;i<10;i++){
  27. User u = new User((long)(1000+i),"LiangYaotian"+i,true,21);
  28. userList.add(u);
  29. }
  30. hello.setUserList(userList);
  31. userList = null;
  32. userList = hello.getUserList();
  33. System.out.println("ArrayList<User> construct from C++,then Java print it.....");
  34. for(User u : userList){
  35. System.out.println("id:"+u.getId()+"; name:"+u.getUserName());
  36. }
  37. }
  38. }

C头文件(HelloJni.h)

[java] view plaincopy
  1. #include <jni.h>
  2. /* Header for class HelloJni */
  3. #ifndef _Included_HelloJni
  4. #define _Included_HelloJni
  5. #ifdef __cplusplus
  6. extern "C" {
  7. #endif
  8. JNIEXPORT void JNICALL Java_HelloJni_sayHello (JNIEnv *, jclass);
  9. JNIEXPORT jint JNICALL Java_HelloJni_getInt (JNIEnv *, jobject);
  10. JNIEXPORT void JNICALL Java_HelloJni_setInt (JNIEnv *, jobject, jint);
  11. JNIEXPORT void JNICALL Java_HelloJni_setUser (JNIEnv *, jobject, jstring);
  12. JNIEXPORT jobject JNICALL Java_HelloJni_getUser  (JNIEnv *, jobject);

头文件的实现(HelloJni.cpp)

[java] view plaincopy
  1. #include "HelloJni.h"
  2. int i=1;
  3. jobject user;
  4. JNIEXPORT jint JNICALL Java_HelloJni_get
  5. (JNIEnv *env, jobject jthiz){
  6. printf("HelloWorld/n");
  7. }
  8. JNIEXPORT void JNICALL Java_HelloJni_set
  9. (JNIEnv *env, jobject jthiz, jint ji){
  10. i = ji+1;
  11. }
  12. JNIEXPORT void JNICALL Java_HelloJni_setUser
  13. (JNIEnv *env, jobject jthiz, jstring name){
  14. jclass userClass = env->FindClass("User");
  15. jmethodID userMethod = env->GetMethodID(userClass,"<init>","()V");
  16. jfieldID mId = env->GetFieldID(userClass,"id","J");
  17. jfieldID mUserName = env->GetFieldID(userClass,"userName","Ljava/lang/String;");
  18. jfieldID mIsMan = env->GetFieldID(userClass,"isMan","Z");
  19. jfieldID mAge = env->GetFieldID(userClass,"age","I");
  20. jobject userObject = env->NewObject(userClass,userMethod);
  21. env->SetObjectField(userObject,mUserName,name);
  22. env->SetLongField(userObject,mId,1001);
  23. env->SetBooleanField(userObject,mIsMan,1);
  24. env->SetIntField(userObject,mAge,21);
  25. user = userObject;
  26. }
  27. JNIEXPORT jobject JNICALL Java_HelloJni_getUser
  28. (JNIEnv *env, jobject jthiz){
  29. return user;
  30. }
  31. JNIEXPORT void JNICALL Java_HelloJni_setUserList
  32. (JNIEnv *env, jobject jthiz, jobject userList){
  33. int i;
  34. //class ArrayList
  35. jclass cls_arraylist = env->GetObjectClass(userList);
  36. //method in class ArrayList
  37. jmethodID arraylist_get = env->GetMethodID(cls_arraylist,"get","(I)Ljava/lang/Object;");
  38. jmethodID arraylist_size = env->GetMethodID(cls_arraylist,"size","()I");
  39. jint len = env->CallIntMethod(userList,arraylist_size);
  40. printf("get java ArrayList<User> object by C++ , then print it...../n");
  41. for(i=0;i<len;i++){
  42. jobject obj_user = env->CallObjectMethod(userList,arraylist_get,i);
  43. jclass cls_user = env->GetObjectClass(obj_user);
  44. jmethodID user_getId = env->GetMethodID(cls_user,"getId","()J");
  45. jmethodID user_getUserName = env->GetMethodID(cls_user,"getUserName","()Ljava/lang/String;");
  46. jmethodID user_isMan = env->GetMethodID(cls_user,"isMan","()Z");
  47. jmethodID user_getAge = env->GetMethodID(cls_user,"getAge","()I");
  48. jstring name = (jstring)env->CallObjectMethod(obj_user,user_getUserName);
  49. jboolean b = true;
  50. const char *namePtr = env->GetStringUTFChars(name,&b);
  51. jlong id = env->CallLongMethod(obj_user,user_getId);
  52. jboolean sex = env->CallBooleanMethod(obj_user,user_isMan);
  53. jint age = env->CallIntMethod(obj_user,user_getAge);
  54. printf("Id:%d; ",id);
  55. printf("Name:%s; ",namePtr);
  56. printf("isMan? %d; ",sex);
  57. printf("Age:%d /n ",age);
  58. }
  59. }
  60. JNIEXPORT jobject JNICALL Java_HelloJni_getUserList
  61. (JNIEnv *env, jobject jthiz){
  62. //ArrayList Object
  63. jclass cls_ArrayList = env->FindClass("java/util/ArrayList");
  64. jmethodID construct = env->GetMethodID(cls_ArrayList,"<init>","()V");
  65. jobject obj_ArrayList = env->NewObject(cls_ArrayList,construct,"");
  66. jmethodID arrayList_add = env->GetMethodID(cls_ArrayList,"add","(Ljava/lang/Object;)Z");
  67. //User Object
  68. jclass cls_user = env->FindClass("User");
  69. //none argument construct function
  70. jmethodID construct_user = env->GetMethodID(cls_user,"<init>","()V");
  71. //new a object
  72. jobject obj_user = env->NewObject(cls_user,construct_user,"");
  73. //get method id
  74. /*
  75. jmethodID user_setId = env->GetMethodID(cls_user,"setId","(J)V");
  76. jmethodID user_setUserName = env->GetMethodID(cls_user,"setUserName","(Ljava/lang/String;)V");
  77. jmethodID user_setMan = env->GetMethodID(cls_user,"setMan","(Z)V");
  78. jmethodID user_setAge = env->GetMethodID(cls_user,"setAge","(I)V");
  79. */
  80. int i;
  81. for(i=0;i<10;i++){
  82. //new a object
  83. jobject obj_user = env->NewObject(cls_user,construct_user,"");
  84. //get field id
  85. jfieldID user_id = env->GetFieldID(cls_user,"id","J");
  86. jfieldID user_name = env->GetFieldID(cls_user,"userName","Ljava/lang/String;");
  87. jfieldID user_isMan = env->GetFieldID(cls_user,"isMan","Z");
  88. jfieldID user_age = env->GetFieldID(cls_user,"age","I");
  89. env->SetLongField(obj_user,user_id,i);
  90. env->SetObjectField(obj_user,user_name,env->NewStringUTF("LiangYaoTian"));
  91. env->SetBooleanField(obj_user,user_isMan,1);
  92. env->SetIntField(obj_user,user_age,21);
  93. env->CallObjectMethod(obj_ArrayList,arrayList_add,obj_user);
  94. }
  95. return obj_ArrayList;
  96. }

运行结果:

转载于:https://www.cnblogs.com/qinjunni/archive/2012/02/20/2359181.html

转 java c++互传arraylist相关推荐

  1. java处理表单变量_jsp处理表单及JS和JAVA变量互传

    1:超连接跳转 我们在超连接的时候,常常连接到一个jsp或者Action,比如: XXX 这样做会有一个问题:在test.jsp中,除你传递的param1和param2参数外,你用request.ge ...

  2. servlet传参给jsp和js与java变量互传(废弃,建议JSP开发使用jstl)

    前端.后端.和js脚本数据交互 1.servlet传参数到jsp页面 1.1 servlet页面发送参数 1.2 jsp页面接收参数 2.jsp页面传参数给servlet 2.1 jsp页面提交参数 ...

  3. ajax与java后端互传数据

    文章目录 后端传到前端(传一个集合,展示成表格) controller层 js部分 前端 向后端传值 js部分 controller层 后端传到前端(传一个集合,展示成表格) controller层 ...

  4. java通过无wifi传数据_没有数据线?使用WiFi实现电脑手机互传文件

    电脑和手机相互传文件是我们常常要做的事情,但都大多依靠数据线来完成.然而,当数据线不在身边或坏了怎么办?这时我们就得想其他的办法了,为此,聪明的网友想到了使用WiFi来实现电脑手机互传文件,而事实上也 ...

  5. Android向:实现同一局域网内两台手机之间的文件互传

    背景 最近要做一个demo,目的是实现局域网内的两台手机之间的文件互传.具体流程如下: 手机 A 从服务器上下载一个 apk 文件到本机上: 手机 A 在自己的某个端口上启动一个 Server 服务, ...

  6. 阿里云 oss 同区域不同桶名的文件互传

    理解:发现阿里云不支持同区域的桶的文件互传,阿里云只支持不同区域的桶文件互传. 同区域,在新加坡创建两个桶,a桶.b桶,想把a桶的文件传到b桶里面以下能实现. @Slf4j public class ...

  7. Socket实现文件互传(一)

    最近一直在做比赛的一个项目,实现客户端和PC端的文件互传,其实一开始在看到这个题目的时候,完全不知道怎么去实现,感觉一脸懵逼,后来在查阅了资料以及相关书籍后了解到可以用Socket来进行通信,通过IO ...

  8. 基于Java Web的传智播客crm企业管理系统的设计与实现

    项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等.这里根据疫情当下,你 ...

  9. 人品测试器(Activity之间互传数据)

    下面这个小程序是为了演示Activity之间怎么互传数据的,主要是intent里面的putExtra函数.基本数据的传输非常简单. package com.example.mytest;import ...

最新文章

  1. php request order,php.ini中的request_order推荐设置,requestorder_PHP教程
  2. 负载均衡算法-处理能力均衡
  3. oracle审计的格式
  4. 论文格式——合适【CSDN】发文
  5. application/x-www-form-urlencoded 与multipart/form-data
  6. 谈谈surging 微服务引擎 2.0的链路跟踪和其它新增功能
  7. 1800万元砸向子公司 点击网络巩固SaaS业务
  8. 汇编分析golang循环
  9. daily news新闻阅读客户端应用源码(兼容iPhone和iPad)
  10. Vue CLI 3 中文文档
  11. matlab gpu加速,Matlab之GPU加速方法
  12. linux输出替换字符串,Linux命令之sed-替换字符串
  13. 15个HTML5播放器插件
  14. neo4j springboot 日志_springBoot 与neo4j的简单整合示例
  15. js 获取输入的首字母拼音
  16. @Cacheable缓存注解使用
  17. 小米开发平台上架APP
  18. Java集合框架是什么?说出一些集合框架的优点?
  19. 共享打印机无法打印?常见的12种解决方法【详解】
  20. 18年大专毕业,转行入职车载测试岗位,薪资13K

热门文章

  1. /var/lib/docker/overlay2/xxxxx no such file or directory docker文件删除引发的问题
  2. 2022-2028中国曝光机市场现状及未来发展趋势
  3. GCC 在 Linux、Windows 系统安装
  4. 【C/S语言】.net平台
  5. Jupyter Magic - Timing(%%time %time %timeit)
  6. AI人工智能天机芯芯片
  7. CodeGen标记循环
  8. 无人驾驶传感器融合技术
  9. 高精地图中导航标识识别
  10. javaWeb——Servlet