Java通过JNI调用C++动态库的完整流程详解

 更新时间:2025年04月09日 09:17:10   作者:颇有几分姿色  
JNI(Java Native Interface),是实现Java/Kotlin与C/C++语言之间交互的桥梁,本文主要为大家介绍了Java通过JNI调用C++动态库的完整流程,需要的可以参考下

介绍使用 JNI 调用 C++ 编写的动态链接库的全过程。

示例环境

项目说明
JDK8
C++ 编译器Visual Studio 2019
Java 开发工具IntelliJ IDEA 2021.3
操作系统Windows 10

Java 项目结构概览

编写 Java 类

在 org.jni.nativejni 包下创建类 HelloWorldJni.java:

package org.jni.nativejni;

public class HelloWorldJni {

    static {
        // 加载 C++ 编译生成的 DLL
        System.load("E:/vsproject/HelloWorld/x64/Release/HelloWorld.dll");
    }

    // native 方法声明
    public native String sayHello(String str1, String str2);
    public native int add(int a, int b);

    public static void main(String[] args) {
        HelloWorldJni hw = new HelloWorldJni();
        System.out.println("拼接字符串:" + hw.sayHello("Hello", "World"));
        System.out.println("相加:" + hw.add(52, 23));
    }
}

生成 JNI 头文件

方法一:使用 javac -h(推荐方式,支持 JDK8+)

在项目根目录下执行命令:

javac -h src/main/jni src/main/java/org/jni/nativejni/HelloWorldJni.java

说明:

  • -h 参数用于指定生成头文件的目录。
  • 这个命令会编译 .java 文件然后生成 .class 文件,同时生成 JNI 头文件。

注意:这个命令会在源码目录中生成 .class 文件,建议在 target/classes 中操作,避免污染源码。

方法二:使用 javah(仅适用于 JDK8)

先使用 Maven 编译项目:

mvn clean install

然后执行:

javah -classpath target/classes -d src/main/jni org.jni.nativejni.HelloWorldJni

说明:

  • -classpath 指定 .class 文件的根路径。
  • -d 指定 JNI 头文件的输出目录。

实现 JNI 层与调用 DLL 方法

使用 Visual Studio 编译生成 DLL

1.创建一个新的 C++ DLL 项目,项目名称为 HelloWorld。

2.添加源文件:

  • HelloWorld.cpp:实现 DLL 的原始功能逻辑。
  • HelloWorldJNI.cpp:实现 JNI 桥接代码。

3.配置项目属性:

C/C++ → 常规 → 附加包含目录中添加:

  • JDK 的 include 目录
  • JDK 的 include/win32 目录

C++ 头文件:HelloWorld.h

#ifndef HELLO_WORLD_H
#define HELLO_WORLD_H

// 导出 HelloWorld 函数
extern "C" __declspec(dllexport) const char* HelloWorld(const char* str1, const char* str2);

// 导出 Add 函数
extern "C" __declspec(dllexport) int Add(int a, int b);

#endif // HELLO_WORLD_H#pragma once

C++ 实现:HelloWorld.cpp

// HelloWorld.cpp
#include "pch.h" // 如果 VS 生成了预编译头文件
#include "HelloWorld.h" // 引入头文件
#include <iostream>
#include <string>

extern "C" __declspec(dllexport) const char* HelloWorld(const char* str1, const char* str2) {
    static std::string result; // 使用静态变量存储返回值,确保返回的指针有效
    result = std::string(str1) + "," + std::string(str2);
    return result.c_str(); // 返回拼接后的 C 字符串
}

// 一个简单的加法函数
extern "C" __declspec(dllexport) int Add(int a, int b) {
    return a + b;
}

JNI 头文件:org_jni_nativejni_HelloWorldJni.h

由 javac -h 或 javah 自动生成,内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_jni_nativejni_HelloWorldJni */

#ifndef _Included_org_jni_nativejni_HelloWorldJni
#define _Included_org_jni_nativejni_HelloWorldJni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     org_jni_nativejni_HelloWorldJni
 * Method:    sayHello
 * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_org_jni_nativejni_HelloWorldJni_sayHello
  (JNIEnv *, jobject, jstring, jstring);

/*
 * Class:     org_jni_nativejni_HelloWorldJni
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_org_jni_nativejni_HelloWorldJni_add
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

JNI 实现:HelloWorldJNI.cpp

#include "pch.h" // 如果 VS 生成了预编译头文件
#include "org_jni_nativejni_HelloWorldJni.h"  // 引入自动生成的 JNI 头文件
#include "HelloWorld.h"    // 引入自定义的头文件,调用已有的 DLL 接口

JNIEXPORT jstring JNICALL Java_org_jni_nativejni_HelloWorldJni_sayHello
(JNIEnv* env, jobject, jstring jStr1, jstring jStr2) {
    // 将 Java 字符串转换为 C 字符串
    const char* str1 = env->GetStringUTFChars(jStr1, nullptr);
    const char* str2 = env->GetStringUTFChars(jStr2, nullptr);

    // 调用 C++ 动态库函数
    const char* result = HelloWorld(str1, str2);

    // 释放 Java 字符串的本地内存
    env->ReleaseStringUTFChars(jStr1, str1);
    env->ReleaseStringUTFChars(jStr2, str2);

    // 将 C 字符串转换为 Java 字符串并返回
    return env->NewStringUTF(result);
}


JNIEXPORT jint JNICALL Java_org_jni_nativejni_HelloWorldJni_add
(JNIEnv*, jobject, jint a, jint b) {
    return Add(a, b); // 调用原始的 Add 函数
}

提示:这里为了演示方便,JNI 桥接代码和业务逻辑放在同一个项目中。实际开发时桥接层要单独封装,便于维护与复用。

Java 调用 DLL 测试

将编译生成的 HelloWorld.dll 放到系统环境变量中,这里这个库没什么其他依赖,都是系统 c 盘中有的,所以直接指到它生成的目录就可以使用了。

运行 Java 主类的输出结果:

拼接字符串:Hello,World
相加:75

总结

梳理一下 Java 调用 C++ DLL 的完整流程。主要包括:

  • 编写 Java 类并声明 native 方法
  • 使用 javac -h 或 javah 生成 JNI 头文件
  • 实现 JNI 桥接层,调用 DLL 中的 C++ 方法
  • 使用 Visual Studio 生成 DLL 文件
  • Java 运行时加载并调用本地方法,或者封装成接口给别人使用。

到此这篇关于Java通过JNI调用C++动态库的完整流程详解的文章就介绍到这了,更多相关Java JNI调用C++动态库内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • mybatis实现批量插入并返回主键(xml和注解两种方法)

    mybatis实现批量插入并返回主键(xml和注解两种方法)

    这篇文章主要介绍了mybatis实现批量插入并返回主键(xml和注解两种方法),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • 如何给yml配置文件的密码加密(SpringBoot)

    如何给yml配置文件的密码加密(SpringBoot)

    这篇文章主要介绍了如何给yml配置文件的密码加密(SpringBoot),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • Java如何Mock FileInputStream问题

    Java如何Mock FileInputStream问题

    这篇文章主要介绍了Java如何Mock FileInputStream问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • 浅谈Spring中HandlerMapping的使用

    浅谈Spring中HandlerMapping的使用

    这篇文章主要介绍了浅谈Spring中HandlerMapping的使用,Spingmvc中的HandlerMapping负责解析请求URL,对应到Handler进行处理,这里的Handler一般为Controller里的一个方法method,也可以为servlet或者Controller等,需要的朋友可以参考下
    2023-08-08
  • Springboot项目javax.validation使用方法详解

    Springboot项目javax.validation使用方法详解

    这篇文章主要介绍了Springboot项目javax.validation使用方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • java正则表达式匹配网页所有网址和链接文字的示例

    java正则表达式匹配网页所有网址和链接文字的示例

    这篇文章主要介绍了java正则表达式匹配网页所有网址和链接文字java正则表达式匹配,需要的朋友可以参考下
    2014-03-03
  • Java虚拟机底层原理详细分析

    Java虚拟机底层原理详细分析

    这篇文章主要介绍了Java虚拟机底层原理详细分析,运行时数据区就是俗称的虚拟机内存,主要包括我们熟悉的堆、栈、本地方法栈、方法区(元空间)、程序计数器,虚拟机调优主要针对的是运行时数据区,也就是虚拟机内存,需要的朋友可以参考下
    2024-01-01
  • JAVA调用JavaScript方法代码示例

    JAVA调用JavaScript方法代码示例

    之前在一次机缘巧合的情况下,需要时用JAVA执行js方法,查阅了一些文档,找到了相关解决方法,这里和大家分享一下,这篇文章主要给大家介绍了关于JAVA调用JavaScript方法的相关资料,需要的朋友可以参考下
    2023-09-09
  • Java8实战之Stream的延迟计算

    Java8实战之Stream的延迟计算

    JDK中Stream的中间函数如 filter(Predicate super T>)是惰性求值的,filter并非对流中所有元素调用传递给它的Predicate,下面这篇文章主要给大家介绍了关于Java8实战之Stream延迟计算的相关资料,需要的朋友可以参考下
    2021-09-09
  • Java实现在线编辑预览office文档详解

    Java实现在线编辑预览office文档详解

    PageOffice是一款在线的office编辑软件,帮助Web应用系统或Web网站实现用户在线编辑Word、Excel、PowerPoint文档,下面我们就来看看如何使用Java实现在线预览office吧
    2024-01-01

最新评论