欢迎来到徐庆高(Tea)的个人博客网站
磨难很爱我,一度将我连根拔起。从惊慌失措到心力交瘁,我孤身一人,但并不孤独无依。依赖那些依赖我的人,信任那些信任我的人,帮助那些给予我帮助的人。如果我愿意,可以分裂成无数面镜子,让他们看见我,就像看见自己。察言观色和模仿学习是我的领域。像每个深受创伤的人那样,最终,我学会了随遇而安。
当前位置: 日志文章 > 详细内容

Java调用C++动态库超详细步骤讲解(附源码)

2025年04月08日 Java
在某些项目中需要在java工程中调用自定义的c++的动态库,分为以下两步,第一步:动态库生成;第二步:java调用动态库。一、直接调用c++库第一步:动态库生成(vs2017+qt5.12.10)1、

在某些项目中需要在java工程中调用自定义的c++的动态库,分为以下两步,第一步:动态库生成;第二步:java调用动态库。

一、直接调用c++库

第一步:动态库生成(vs2017+qt5.12.10)

1、新建工程时,一定要选择qt下的qt class library 这个选项,如下图所示

2、工程创建成功后,可以在解决方案下看到有testlib.h、testlib.cpp和testlib_global.h三个基础的文件生成,如下图所示

3、下面我们简单写一个打印“vs2017+qt5.12.10生成动态库”的输出函数

testlib_global.h

#pragma once

#include <qtcore/qglobal.h>
#include <qdebug>

#include "jni.h"


#ifndef build_static
# if defined(testlib_lib)
#  define testlib_export q_decl_export
# else
#  define testlib_export q_decl_import
# endif
#else
# define testlib_export
#endif

testlib.h

#pragma once

#include "testlib_global.h"

class testlib_export testlib
{
public:
    testlib();

	/**************************************************
	* @author 鬼魅-9527
	* @brief : 打印
	* @param-in: 无
	* @param-out : 无
	* @return : 是否成功
	* @date : 2025-01-01
	**************************************************/
	bool java_sdk_printfstring();
};

/*将接口转义供外部调用*/
extern "c"
{
	testlib obj;
	extern "c" _declspec(dllexport) bool __cdecl java_sdk_printfstring()
	{
		return obj.java_sdk_printfstring();
	}
}

testlib.cpp

#include "testlib.h"

testlib::testlib()
{
}

bool testlib::java_sdk_printfstring()
{
	/*使用qstringliteral,否则中文输出会乱码*/
	qdebug() << qstringliteral("vs2017+qt5.12.10生成动态库");

	return true;
}

注:java调用的c++动态库和python调用的动态库有不同的地方,在于接口的命名方式上,c++中接口命名必须以java+javaclassname+接口名,如:java_sdk_printfstring。

4、下面我们可以编译生成动态库

第二步:java调用c++动态库

1、打开vs code 并在动态库目录下新建一个test.java文件

test.java

public class sdk {
    // 声明native方法
    public native boolean printfstring();
    // 加载库
    static {
        system.loadlibrary("testlib"); // 对于windows, 可能是"example.dll"; 对于linux, 可能是"libexample.so"
    } 
    public static void main(string[] args) {
        sdk ex = new sdk();
        boolean result = ex.printfstring();
        system.out.println(result); 
    }
}

2、运行tets.java,如下所示

注:如果运行提示找不到动态库,将对应的动态库和对应依赖的库拷贝到java执行目录bin下面。

二、调用带参数传递的c++库

在大多数情况下,我们使用动态库调用时,都涉及参数传递,以下是简单的参数传递列子。

注:在封装传参数的接口给java使用时,需要使用到java对c++提供的参数名,因此需要将java安装目录下的include文件夹拷贝到工程中,并在工程中添加jni.h文件(重之重‘~_~)

第一步:动态库封装

testlib_global.h

#pragma once

#include <qtcore/qglobal.h>
#include <qdebug>

#include "jni.h"


#ifndef build_static
# if defined(testlib_lib)
#  define testlib_export q_decl_export
# else
#  define testlib_export q_decl_import
# endif
#else
# define testlib_export
#endif

testlib.h

#pragma once

#include "testlib_global.h"

class testlib_export testlib
{
public:
    testlib();

	/**************************************************
	* @author 鬼魅-9527
	* @brief : 打印
	* @param-in: 无
	* @param-out : 无
	* @return : 是否成功
	* @date : 2025-01-01
	**************************************************/
	bool java_sdk_printfstring();
	/**************************************************
	* @author 鬼魅-9527
	* @brief : 参数传递
	* @param-in: num:数量,str;字符串
	* @return :字符串长度
	* @date : 2025-01-01
	**************************************************/
	jint java_sdk_datainputandoutput(jnienv *env, jobject _obj, const jint num, const jstring str);
};

/*将接口转义供外部调用*/
extern "c"
{
	testlib obj;
	extern "c" _declspec(dllexport) bool __cdecl java_sdk_printfstring()
	{
		return obj.java_sdk_printfstring();
	}
	extern "c" _declspec(dllexport) jint __cdecl java_sdk_datainputandoutput(jnienv *env, jobject _obj, const jint num, const jstring str)
	{
		return obj.java_sdk_datainputandoutput(env, _obj, num, str);
	}
}

注:java调用的c++传参的动态库,命名规则为:返回值 java_类名_函数名(jnienv* env,jobject obj,参数1,参数2 ,等);

如:jint java_sdk_ava_sdk_datainputandoutput(jnienv *env, jobject _obj, const jint num, const jstring str);
参数jnienv *env就是初始化虚拟机得到的jni环境;

参数jobject _obj为该类的对象;

参数const jint num位参数1;

参数const jstring str为参数2。

其中(jint、jstring为jni.h文件中,对应java中的int和string)

test.cpp

#include "testlib.h"

testlib::testlib()
{
}

bool testlib::java_sdk_printfstring()
{
	/*使用qstringliteral,否则中文输出会乱码*/
	qdebug() << qstringliteral("vs2017+qt5.12.10生成动态库");

	return true;
}

jint testlib::java_sdk_datainputandoutput(jnienv *env, jobject _obj, const jint num, const jstring str)
{
    /*jstring转string*/
	std::string stdstr(env->getstringutfchars(str, null));
	env->releasestringutfchars(str, null);
	qdebug() << "input num:" << num << "input str:" << qstring::fromstdstring(stdstr);

	return num +stdstr.size();
}

4、编译生成动态库

第二步:java调用c++动态库

1、打开vs code 并在动态库目录下新建一个test.java文件

test.java

public class sdk {
    // 声明native方法
    public native boolean printfstring();
    public native int datainputandoutput(int num, string str);
    // 加载库
    static {
        system.loadlibrary("testlib"); // 对于windows, 可能是"example.dll"; 对于linux, 可能是"libexample.so"
    } 
    public static void main(string[] args) {
        sdk ex = new sdk();
        boolean result = ex.printfstring();
        system.out.println(result); 
        int num = 10;
        string str = "z:/demo/testlib/x64/release/testlib.dll";
        int len = ex.datainputandoutput(num,str);
        system.out.println(len); 
    }
}

2、运行tets.java,如下所示

注:如果运行提示找不到动态库,将对应的动态库和对应依赖的库拷贝到java执行目录bin下面。

总结

到此这篇关于java调用c++动态库的文章就介绍到这了,更多相关java调用c++动态库内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!