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

我们知道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):

import java.util.*;  
public class HelloJni{  

    static{  
        System.loadLibrary("hello");  
    }  
    public native static void sayHello();  
    public static void main(String [] args)  
    {  
                HelloJni.sayHello();  
    }  
}  

生成头文件(HelloJni.h):

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

头文件内容是这样的:

/* DO NOT EDIT THIS FILE - it is machine generated */  
#include   
/* Header for class HelloJni */  
#ifndef _Included_HelloJni  
#define _Included_HelloJni  
#ifdef __cplusplus  
extern "C" {  
#endif  
JNIEXPORT void JNICALL Java_HelloJni_sayHello (JNIEnv *, jclass);  
#ifdef __cplusplus  
}  
#endif  
#endif  

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

#include "HelloJni.h"  
JNIEXPORT void JNICALL Java_HelloJni_sayHello(JNIEnv *env, jclass cls)  
{  
       printf("HelloWorld");  
}  

编译命令: g++ -I JAVAHOME/includeI 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):

public class HelloJni{  
        static{  
                   System.loadLibrary("hello");  
        }  
        public static native void sayHello();  
        public native int getInt();  
        public native void setInt(int i);  
        public static void main(String args[]){  
        //      HelloJni.sayHello();  
                 HelloJni hello = new HelloJni();  
                 hello.setInt(2);  
                 System.out.println(hello.getInt());  
        }  
}  

生成头文件(HelloJni.h):

/* DO NOT EDIT THIS FILE - it is machine generated */  
#include   
/* Header for class HelloJni */  
#ifndef _Included_HelloJni  
#define _Included_HelloJni  
#ifdef __cplusplus  
extern "C" {  
#endif  
JNIEXPORT void JNICALL Java_HelloJni_sayHello (JNIEnv *, jclass);  
JNIEXPORT jint JNICALL Java_HelloJni_getInt (JNIEnv *, jobject);  
JNIEXPORT void JNICALL Java_HelloJni_setInt (JNIEnv *, jobject, jint);  
#ifdef __cplusplus  
}  
#endif  
#endif  

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

#include "HelloJni.h"  
int i=1;  
JNIEXPORT void JNICALL Java_HelloJni_sayHello  
  (JNIEnv *env, jclass cls){  
        printf("HelloWorld/n");  
}  
JNIEXPORT jint JNICALL Java_HelloJni_getInt  
  (JNIEnv *env, jobject thiz){  
        return i;  
}  
JNIEXPORT void JNICALL Java_HelloJni_setInt  
  (JNIEnv *env, jobject thiz,jint ji){  
        i = ji+1;  
}  

运行结果:打印2

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

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

public class User{  
        private long id;  
        private String userName;  
        private boolean isMan;  
        private int age;  
        public User(){}  
        public User(long id, String userName, boolean isMan, int age) {  
                super();  
                this.id = id;  
                this.userName = userName;  
                this.isMan = isMan;  
                this.age = age;  
        }  
        public long getId() {  
                return id;  
        }  
        public void setId(long id) {  
                this.id = id;  
        }  
        public String getUserName() {  
                return userName;  
        }  
        public void setUserName(String userName) {  
                this.userName = userName;  
        }  
        public boolean isMan() {  
                return isMan;  
        }  
        public void setMan(boolean isMan) {  
                this.isMan = isMan;  
        }  
        public int getAge() {  
                return age;  
        }  
        public void setAge(int age) {  
                this.age = age;  
        }  
}  

Java代码(HelloJni.java):

public class HelloJni{  
        static{  
                System.loadLibrary("userbean");  
        }  
        public static native void sayHello();  
        public native int getInt();  
        public native void setInt(int i);  
        public native void setUser(String userName);  
        public native User getUser();  
        public static void main(String args[]){  
        //      HelloJni.sayHello();  
                HelloJni hello = new HelloJni();  
        //      hello.setInt(2);  
        //      System.out.println(hello.getInt());  
                hello.setUser("LiangYaotian");  
                User user = hello.getUser();  
                System.out.println("user from c/c++");  
                System.out.println("name:"+user.getUserName());  
                System.out.println("isMan?:"+user.isMan());  
                System.out.println("age:"+user.getAge());  
        }  
}   

生成头文件(HelloJni.h):

#include   
/* Header for class HelloJni */  
#ifndef _Included_HelloJni  
#define _Included_HelloJni  
#ifdef __cplusplus  
extern "C" {  
#endif  
JNIEXPORT void JNICALL Java_HelloJni_sayHello (JNIEnv *, jclass);  
JNIEXPORT jint JNICALL Java_HelloJni_getInt (JNIEnv *, jobject);  
JNIEXPORT void JNICALL Java_HelloJni_setInt (JNIEnv *, jobject, jint);  
JNIEXPORT void JNICALL Java_HelloJni_setUser (JNIEnv *, jobject, jstring);  
JNIEXPORT jobject JNICALL Java_HelloJni_getUser  (JNIEnv *, jobject);  
#ifdef __cplusplus  
}  
#endif  
#endif 

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

#include   
#include   
using namespace std;  
int i=1;  
jobject user;  
JNIEXPORT void JNICALL Java_HelloJni_sayHello  
  (JNIEnv *env, jclass cls){  
        printf("HelloWorld/n");  
}  
JNIEXPORT jint JNICALL Java_HelloJni_getInt  
  (JNIEnv *env, jobject thiz){  
        return i;  
}  
JNIEXPORT void JNICALL Java_HelloJni_setInt  
  (JNIEnv *env, jobject thiz,jint ji){  
        i = ji+1;  
}  
JNIEXPORT void JNICALL Java_HelloJni_setUser  
  (JNIEnv *env, jobject thiz, jstring name){  
        jclass userClass = env->FindClass("User");  
        jmethodID userMethod = env->GetMethodID(userClass,"","()V");  
        jfieldID mId = env->GetFieldID(userClass,"id","J");  
        jfieldID mUserName = env->GetFieldID(userClass,"userName","Ljava/lang/String;");  
        jfieldID mIsMan = env->GetFieldID(userClass,"isMan","Z");  
        jfieldID mAge = env->GetFieldID(userClass,"age","I");  
        jobject userObject = env->NewObject(userClass,userMethod);  
        env->SetObjectField(userObject,mUserName,name);  
        env->SetLongField(userObject,mId,1001);  
        env->SetBooleanField(userObject,mIsMan,1);  
        env->SetIntField(userObject,mAge,21);  
        user = userObject;  
}  

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

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

Java代码(User.java)

同上。

Java代码(HelloJni.java)

import java.util.*;  
public class HelloJni{  
        static{  
                System.loadLibrary("userbean");  
        }  
        public native int get();  
        public native void set(int i);  
        public native void setUser(String userName);  
        public native User getUser();  
        public native void setUserList(ArrayList userList);  
        public native ArrayList getUserList();  
        public static void main(String [] args)  
        {  
                HelloJni hello = new HelloJni();  
        //      hello.set(2);  
        //      System.out.println(hello.get());  
        /* 
                hello.setUser("LiangYaotian"); 
                User user = hello.getUser(); 
                System.out.println("user from c/c++"); 
                System.out.println("name:"+user.getUserName()); 
                System.out.println("isMan?:"+user.isMan()); 
                System.out.println("age:"+user.getAge()); 
        */  
                ArrayList userList = new ArrayList();  
                for(int i=0;i<10;i++){  
                        User u = new User((long)(1000+i),"LiangYaotian"+i,true,21);  
                        userList.add(u);  
                }  
                hello.setUserList(userList);  
                userList = null;  
                userList = hello.getUserList();  
                System.out.println("ArrayList construct from C++,then Java print it.....");  
                for(User u : userList){  
                        System.out.println("id:"+u.getId()+"; name:"+u.getUserName());  
                }  
        }  
}  

C头文件(HelloJni.h)

#include   
/* Header for class HelloJni */  
#ifndef _Included_HelloJni  
#define _Included_HelloJni  
#ifdef __cplusplus  
extern "C" {  
#endif  
JNIEXPORT void JNICALL Java_HelloJni_sayHello (JNIEnv *, jclass);  
JNIEXPORT jint JNICALL Java_HelloJni_getInt (JNIEnv *, jobject);  
JNIEXPORT void JNICALL Java_HelloJni_setInt (JNIEnv *, jobject, jint);  
JNIEXPORT void JNICALL Java_HelloJni_setUser (JNIEnv *, jobject, jstring);  
JNIEXPORT jobject JNICALL Java_HelloJni_getUser  (JNIEnv *, jobject);  

头文件的实现(HelloJni.cpp)

#include "HelloJni.h"  
int i=1;  
jobject user;  
JNIEXPORT jint JNICALL Java_HelloJni_get  
  (JNIEnv *env, jobject jthiz){  
        printf("HelloWorld/n");  
}  
JNIEXPORT void JNICALL Java_HelloJni_set  
  (JNIEnv *env, jobject jthiz, jint ji){  
        i = ji+1;  
}  
JNIEXPORT void JNICALL Java_HelloJni_setUser  
  (JNIEnv *env, jobject jthiz, jstring name){  
        jclass userClass = env->FindClass("User");  
        jmethodID userMethod = env->GetMethodID(userClass,"","()V");  
        jfieldID mId = env->GetFieldID(userClass,"id","J");  
        jfieldID mUserName = env->GetFieldID(userClass,"userName","Ljava/lang/String;");  
        jfieldID mIsMan = env->GetFieldID(userClass,"isMan","Z");  
        jfieldID mAge = env->GetFieldID(userClass,"age","I");  
        jobject userObject = env->NewObject(userClass,userMethod);  
        env->SetObjectField(userObject,mUserName,name);  
        env->SetLongField(userObject,mId,1001);  
        env->SetBooleanField(userObject,mIsMan,1);  
        env->SetIntField(userObject,mAge,21);  
        user = userObject;  
}  
JNIEXPORT jobject JNICALL Java_HelloJni_getUser  
  (JNIEnv *env, jobject jthiz){  
        return user;  
}  
JNIEXPORT void JNICALL Java_HelloJni_setUserList  
  (JNIEnv *env, jobject jthiz, jobject userList){  
        int i;  
        //class ArrayList  
        jclass cls_arraylist = env->GetObjectClass(userList);  
        //method in class ArrayList  
        jmethodID arraylist_get = env->GetMethodID(cls_arraylist,"get","(I)Ljava/lang/Object;");  
        jmethodID arraylist_size = env->GetMethodID(cls_arraylist,"size","()I");  
        jint len = env->CallIntMethod(userList,arraylist_size);  
        printf("get java ArrayList object by C++ , then print it...../n");  
        for(i=0;iobject obj_user = env->CallObjectMethod(userList,arraylist_get,i);  
                jclass cls_user = env->GetObjectClass(obj_user);  
                jmethodID user_getId = env->GetMethodID(cls_user,"getId","()J");  
                jmethodID user_getUserName = env->GetMethodID(cls_user,"getUserName","()Ljava/lang/String;");  
                jmethodID user_isMan = env->GetMethodID(cls_user,"isMan","()Z");  
                jmethodID user_getAge = env->GetMethodID(cls_user,"getAge","()I");  
                jstring name = (jstring)env->CallObjectMethod(obj_user,user_getUserName);  
                jboolean b = true;  
                const char *namePtr = env->GetStringUTFChars(name,&b);  
                jlong id = env->CallLongMethod(obj_user,user_getId);  
                jboolean sex = env->CallBooleanMethod(obj_user,user_isMan);  
                jint age = env->CallIntMethod(obj_user,user_getAge);  
                printf("Id:%d; ",id);  
                printf("Name:%s; ",namePtr);  
                printf("isMan? %d; ",sex);  
                printf("Age:%d /n ",age);  
        }  
}  
JNIEXPORT jobject JNICALL Java_HelloJni_getUserList  
  (JNIEnv *env, jobject jthiz){  
        //ArrayList Object  
        jclass cls_ArrayList = env->FindClass("java/util/ArrayList");  
        jmethodID construct = env->GetMethodID(cls_ArrayList,"","()V");  
        jobject obj_ArrayList = env->NewObject(cls_ArrayList,construct,"");  
        jmethodID arrayList_add = env->GetMethodID(cls_ArrayList,"add","(Ljava/lang/Object;)Z");  
        //User Object  
        jclass cls_user = env->FindClass("User");  
        //none argument construct function  
        jmethodID construct_user = env->GetMethodID(cls_user,"","()V");  
        //new a object  
        jobject obj_user = env->NewObject(cls_user,construct_user,"");  
        //get method id  
        /* 
        jmethodID user_setId = env->GetMethodID(cls_user,"setId","(J)V"); 
        jmethodID user_setUserName = env->GetMethodID(cls_user,"setUserName","(Ljava/lang/String;)V"); 
        jmethodID user_setMan = env->GetMethodID(cls_user,"setMan","(Z)V"); 
        jmethodID user_setAge = env->GetMethodID(cls_user,"setAge","(I)V"); 
        */  
        int i;  
        for(i=0;i<10;i++){  
        //new a object  
        jobject obj_user = env->NewObject(cls_user,construct_user,"");  
        //get field id  
        jfieldID user_id = env->GetFieldID(cls_user,"id","J");  
        jfieldID user_name = env->GetFieldID(cls_user,"userName","Ljava/lang/String;");  
        jfieldID user_isMan = env->GetFieldID(cls_user,"isMan","Z");  
        jfieldID user_age = env->GetFieldID(cls_user,"age","I");  
        env->SetLongField(obj_user,user_id,i);  
        env->SetObjectField(obj_user,user_name,env->NewStringUTF("LiangYaoTian"));  
        env->SetBooleanField(obj_user,user_isMan,1);  
        env->SetIntField(obj_user,user_age,21);  
                env->CallObjectMethod(obj_ArrayList,arrayList_add,obj_user);  
        }  
        return obj_ArrayList;  
}  

运行结果:

theEnd.jpg

源码:E-Mail我:[email protected]

原创作品,转载需注明出处…http://blog.csdn.net/u_xtian/archive/2010/11/25/6033963.aspx

你可能感兴趣的:(Java JNI由浅入深(包括:Java和C++互传ArrayList泛型对象参数))