将c++静态库实现二次封装供java调用

简介: 工作中常常作为c++开发者,常常需要与java开发人员进行对接,或者他们看重了一些很好的c++库想借用,就需要将这些已有的开发可进行二次封装给java开发调用首先需要从官网下载jdk并安装,例如本人的安装路径:C:\software\java\jdk1.

工作中常常作为c++开发者,常常需要与java开发人员进行对接,或者他们看重了一些很好的c++库想借用,就需要将这些已有的开发可进行二次封装给java开发调用

首先需要从官网下载jdk并安装,例如本人的安装路径:C:\software\java\jdk1.8.0_45\

假如我们目前已有一组c++的头文件及库文件

[1]建立对应的java类及结构

c++头文件ReData.h里有一个结构数据:

///ReData.h

struct MSGItem
{
    MSGItem() : chl_id(0), t_sec(0),t_usec(0),_direct(0),_msg("")
    {
    };
    ~MSGItem()
    {
    };
    MSGItem& operator=(const MSGItem& rhs)
    {
        if(this!=&rhs){
            this->chl_id = rhs.chl_id;
            this->t_sec = rhs.t_sec;
            this->t_usec = rhs.t_usec;
            this->_direct = rhs._direct;
            this->_msg = rhs._msg;
        }
        return *this;
    };
    unsigned int chl_id;
    unsigned int  t_sec;         /* seconds */
    unsigned int  t_usec;        /* and microseconds */
    int _direct;
    std::string _msg;
};

//ReData.h

假如有一个MSGRecive类,并该类引用了MSGItem结构,

//MSGRecive.h

class MSGRecive
{
public:
    MSGRecive(void);
    ~MSGRecive(void);

public:

.......................................

    //获取报文数据
    bool getMsg(MSGItem &_item);

    //取对应ip的设备id
    int GetIDByIP(int _id);
    //批量取对应ip的设备id
    int GetIDByIPRange(int _startId, int _endId,std::map<int,int> &_idMaps);

.......................................................

};

//MSGRecive.h

现在建立java与c++结构数据对应的结构及类,例如

建立一个java工程,在src\lib_et1100目录下建立对应的java类

//JMSGItem.java

package lib_et1100;

public class JMSGItem {
    public int chl_id;
    public int  t_sec;         /* seconds */
    public int  t_usec;        /* and microseconds */
    public int _direct;
    public String _msg;
}

//JMSGItem.java


//JMSGRecive.java

package lib_et1100;

import java.util.Map;
import lib_et1100.JMSGItem;

public class JMSGRecive {

    static
    {
        System.loadLibrary("jk_dll");
    }
    public JMSGRecive()
    {
        mNativeMSGRecive = init();
    }

........................................................

    //获取报文数据
    public boolean getMsg(JMSGItem _item)
    {
        return getMsg_c(mNativeMSGRecive,_item);
    }
    //取对应ip的设备id
    public int GetIDByIP(int _id)
    {
        return GetIDByIP_c(mNativeMSGRecive,_id);
    }
    //批量取对应ip的设备id
    public int GetIDByIPRange(int _startId, int _endId, Map _idMaps)
    {
        return GetIDByIPRange_c(mNativeMSGRecive,_startId,_endId,_idMaps);
    }

........................................................................................

    private native int  init();

    private native int GetIDByIP_c(int mMSGRecive,int _id);
    private native boolean getMsg_c(int mMSGRecive,JMSGItem _item);
    private native int GetIDByIPRange_c(int mMSGRecive,int _startId, int _endId, Map _idMaps);

    private int mNativeMSGRecive;
}

//JMSGRecive.java

//LibJavaEt.java,主程序类

package lib_et1100;

public class LibJavaEt {

     public static void main(String[] args) {

            JMSGRecive msg = new JMSGRecive();

           ..............................................................

          JMSGItem it = new JMSGItem();
          boolean ret = msg.getMsg(it);

         .....................................................................

     }

}

//LibJavaEt.java

[2]使用javah命令(javah  类的全路径)

javah  .classpath -jni

//////////////////.classpath conf///////////////

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
    <classpathentry kind="src" path="src"/>
    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
    <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/jk_dll">
        <attributes>
            <attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="jk_lib_sample/bin"/>
        </attributes>
    </classpathentry>
    <classpathentry kind="output" path="bin"/>
</classpath>

///////////////////////////////////////////////

.classpath配置java源src及输出bin目录,

然后生成本地方法的C++头文件,例如lib_et1100_JMSGRecive.h到bin目录,并在bin下会生成一组对应的java的.class文件,

例如lib_et1100/JMSGItem.class, lib_et1100/JMSGRecive.class,

在lib_et1100_JMSGRecive.h文件中,lib_et1100_JMSGRecive对应lib_et1100/JMSGItem.class的输出

javah .classpath

//lib_et1100_JMSGRecive.h

#include <jni.h>

#ifdef __cplusplus
extern "C" {
#endif

..................................................................................................

/*
 * Class:     lib_et1100_JMSGRecive
 * Method:    init
 * Signature: ()I
 */

JNIEXPORT jint JNICALL Java_lib_1et1100_JMSGRecive_init
  (JNIEnv *, jobject);

/*
 * Class:     lib_et1100_JMSGRecive
 * Method:    getMsg_c
 * Signature: (ILlib_et1100/JMSGItem;)Z
 */
JNIEXPORT jboolean JNICALL Java_lib_1et1100_JMSGRecive_getMsg_1c
  (JNIEnv *, jobject, jint, jobject);

/*
 * Class:     lib_et1100_JMSGRecive
 * Method:    GetIPByID_c
 * Signature: (II)I
 */

JNIEXPORT jint JNICALL Java_lib_1et1100_JMSGRecive_GetIDByIP_1c
  (JNIEnv *, jobject, jint obj, jint _id);

/*
 * Class:     lib_et1100_JMSGRecive
 * Method:    GetIDByIPRange_c
 * Signature: (IIILjava/util/Map;)I
 */

JNIEXPORT jint JNICALL Java_lib_1et1100_JMSGRecive_GetIDByIPRange_1c
  (JNIEnv *env, jobject, jint obj, jint startId, jint endId, jobject rmap);
........................................................................

#ifdef __cplusplus
}
#endif

//lib_et1100_JMSGRecive.h


[3]需要建立一个c++项目将这些库封装成java调用的动态库,

我们建立一个c++项目并设置jdk的头及库调用

C:\software\java\jdk1.8.0_45\include

C:\software\java\jdk1.8.0_45\include\win

C:\software\java\jdk1.8.0_45\lib

同时将需要java调用的c++的头及库文件加入项目

并将javah命令生成的头文件加入到项目中,

[4]c++数据结构转换Java数据结构

我们在StructDataTran.h将c++结构数据进行转换

//StructDataTran.h

#include <jni.h>//JNI是Java Native Interface的缩写,中文为JAVA本地调用。使用JNI可以很方便的用我们的Java程序调用C/C++程序。

#include <map>

#include "ReData.h"

void cp_msgitem(JNIEnv *env,MSGItem_item,jobject ritem)

{
    jclass ritem_c = env->GetObjectClass(ritem);
    if(NULL!=ritem_c)
    {
        //获取相关数据;
        jfieldID _direct = env->GetFieldID(ritem_c,"_direct","I");
        jfieldID chl_id = env->GetFieldID(ritem_c,"chl_id","I");
        jfieldID t_sec = env->GetFieldID(ritem_c,"t_sec","I");
        jfieldID t_usec = env->GetFieldID(ritem_c,"t_usec","I");

        jfieldID _msg = env->GetFieldID(ritem_c,"_msg","Ljava/lang/String;");

        //设置相关数据
        env->SetIntField(ritem,_direct,_item._direct);
        env->SetIntField(ritem,chl_id,_item.chl_id);
        env->SetIntField(ritem,t_sec,_item.t_sec);
        env->SetIntField(ritem,t_usec,_item.t_usec);

        jstring str = env->NewStringUTF(_item._msg.c_str());
        env->SetObjectField(ritem,_msg,str);
    }

};

//还需要转换标准库的一些结构及容器类

void cp_map(JNIEnv *env,std::map<int,int> _idMaps,jobject rmap)
{
    if(!_idMaps.empty()){    
        jclass ritem_c = env->GetObjectClass(rmap);
        //jclass ritem_c = env->FindClass("java/util/HashMap");
        if(NULL!=ritem_c)
        {
            jmethodID HashMap_put = env->GetMethodID(ritem_c, "put",
                "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
            if (HashMap_put == NULL)
                printf("method ID jput not valid\n\n");
            else
            {
                for(std::map<int,int>::iterator it=_idMaps.begin();it!=_idMaps.end();it++)
                {
                    char key[64]={0};
                    itoa(it->first,key,10);
                    char val[64]={0};
                    itoa(it->second,val,10);
                    env->CallVoidMethod(rmap,HashMap_put,env->NewStringUTF(key),env->NewStringUTF(val));
                }
            }
        }
    }
};

[5]实现javah命令生成的头文件的源代码

///lib_et1100_JMSGRecive.cpp

#include "lib_et1100_JMSGRecive.h"

#include "MSGRecive.h"
#include "StructDataTran.h"

..................................................................................................

JNIEXPORT jint JNICALL Java_lib_1et1100_JMSGRecive_init
  (JNIEnv *, jobject)

{
    MSGRecive* p = new MSGRecive();
    return (jint)p;
};


JNIEXPORT jboolean JNICALL Java_lib_1et1100_JMSGRecive_getMsg_1c
  (JNIEnv *, jobject, jint, jobject)

{
    MSGRecive* p = (MSGRecive*)obj;
    MSGItem _item;
    jboolean ret = p->getMsg(_item);
    if(!ret){
        printf("getMsg error!\n");
    }else{
        cp_msgitem(env,_item,ritem);
    }
    return ret;
};


JNIEXPORT jint JNICALL Java_lib_1et1100_JMSGRecive_GetIDByIP_1c
  (JNIEnv *, jobject, jint obj, jint _id)
{
    MSGRecive* p = (MSGRecive*)obj;
    return p->GetIDByIP(_id);
};

JNIEXPORT jint JNICALL Java_lib_1et1100_JMSGRecive_GetIDByIPRange_1c
  (JNIEnv *env, jobject, jint obj, jint startId, jint endId, jobject rmap)
{
    MSGRecive* p = (MSGRecive*)obj;
    std::map<int,int> _idMaps;
    jint ret = p->GetIDByIPRange(startId,endId,_idMaps);
    cp_map(env,_idMaps,rmap);
    return ret;
};

........................................................................

///lib_et1100_JMSGRecive.cpp

//最终项目生成一个dll文件,例如jk_dll.dll文件,将动态库输出到java工程的bin里,

[6]java调用

现在在java工程里,这些java的类及结构数据调用类似

注意JNI为JAVA本地调用,会丧失平台可移植性,工程结构如下

java工程:
jk_et1100_interface
    bin
        lib_et1100
            JMSGItem.class
            JMSGRecive.class
            LibJavaEt.class
        jk_dll.dll
        lib_et1100_JMSGRecive.h
    src
        lib_et1100
            JMSGItem.java
            JMSGRecive.java
            LibJavaEt.java
    .classpath
    .project
jk_dll库项目:
jk_dll
    jk_et1100_interface
        bin
            lib_et1100_JMSGRecive.h
    c++lib
        ReData.h
        MSGRecive.h
        c++Lib.lib
    src
        lib_et1100_JMSGRecive.cpp
        StructDataTran.h
        StructDataTran.cpp


梳理一下,首先知道 c++lib的头文件及库需要调用,然后在java工程/src/lib_et1100建立对应的java类

通过javah命令生成java工程下,bin下的c++头文件及/bin/lib_et110的.class文件,

然后建立库工程jk_dll,将c++lib的头文件及库以及javah命令输出的头文件加载到项目,并实现javah命令输出的头文件的源代码,

jk_dll项目生成动态库到java工程bin下,供java项目使用


目录
相关文章
|
11天前
|
存储 C++ 容器
C++STL(标准模板库)处理学习应用案例
【4月更文挑战第8天】使用C++ STL,通过`std:vector`存储整数数组 `{5, 3, 1, 4, 2}`,然后利用`std::sort`进行排序,输出排序后序列:`std:vector<int> numbers; numbers = {5, 3, 1, 4, 2}; std:sort(numbers.begin(), numbers.end()); for (int number : numbers) { std::cout << number << " "; }`
17 2
|
14天前
|
安全 Java 数据安全/隐私保护
|
14天前
|
搜索推荐 Java
Java的面向对象特性主要包括封装、继承和多态
【4月更文挑战第5天】Java的面向对象特性主要包括封装、继承和多态
13 3
|
23天前
|
算法 编译器 C语言
【C++ 异常】C++ 标准库异常类及其应用
【C++ 异常】C++ 标准库异常类及其应用
17 0
|
7天前
|
算法 Java C语言
C++和Java中的随机函数你玩明白了吗?内附LeetCode470.rand7()爆改rand10()巨详细题解,带你打败LeetCode%99选手
C++和Java中的随机函数你玩明白了吗?内附LeetCode470.rand7()爆改rand10()巨详细题解,带你打败LeetCode%99选手
|
24天前
|
存储 JSON 安全
【C++ JSON库 json值的创建手段】深入探究C++中JSON对象定位与操作:从引用到回调函数
【C++ JSON库 json值的创建手段】深入探究C++中JSON对象定位与操作:从引用到回调函数
60 0
|
23天前
|
缓存 算法 C语言
【C++ 标准查找算法 】C++标准库查找算法深入解析(In-depth Analysis of C++ Standard Library Search Algorithms)
【C++ 标准查找算法 】C++标准库查找算法深入解析(In-depth Analysis of C++ Standard Library Search Algorithms)
45 0
|
24天前
|
Linux C++ iOS开发
【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南(二)
【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南
237 2
|
24天前
|
Linux API C++
【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南(一)
【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南
293 2
|
16天前
|
XML JSON JavaScript
推荐一个比较好用的c++版本http协议库-cpp-httplib
推荐一个比较好用的c++版本http协议库-cpp-httplib
36 1

热门文章

最新文章