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

2025-04-08 15:50

本文主要是介绍Java调用C++动态库超详细步骤讲解(附源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代...

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

一、直接调用C++库

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

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

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

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

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

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++动态库超详细步骤讲解(附源码)

第二步: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调用C++动态库超详细步骤讲解(附源码)

注:如果运行提示找不到动态库,将对应的动态库和对应依赖的库拷贝到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++动态库超详细步骤讲解(附源码)

第二步: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);
 QQhnEvb   // 加载库
    static {
        System.loadLibrary("testLib"); // 对于Windows, 可能是"example.dll"; 对于Linux, 可能是"libexample.so"
China编程    } 
    public static void main(String[] args) {
        SDK ex = new SDK();
        boolean result = ex.China编程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调用C++动态库超详细步骤讲解(附源码)

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

总结

到此这篇关于Java调用C++动态库的文章就介绍android到这了,更多相关Java调用C++动态库内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于Java调用C++动态库超详细步骤讲解(附源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1154134

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三