Java 通过 JNI 调用 C/C++ 类库

时间:2022-08-10 20:20:52

【另外一篇:https://blog.csdn.net/whustyle/article/details/49123933

https://blog.csdn.net/danielpei1222/article/details/62462497

注意:红色字体部分是我 在原文基础上加进去的,也是我实践当中卡壳的地方。

说明

由于一些涉及到设备或底层操作的类库,大多是C或C++语言编写的,对于Java Web开发者,在涉及到相应的项目中,不可能再去将相应的类库用Java重写。这时,就需要通过Java代码去调用C/C++的类库来完成工作。

操作环境: 
- JDK 1.8.0_45 
- Eclipse 
- Visual Studio 2013

注意: demo中的文件路径需要加以注意!!!

演示实现

整体目标

通过Java调用C++代码编写的 *.dll 类库中封装的方法,本 Demo 中包含两个方法,一个是输出文本信息,无返回值;一个计算并返回两个整数之和。

编写Java接口

package com.daniel;

/** * JNI 测试类 JNI_Test.java * @author PeiXQ */
public class JNI_Test {
    /** * 打印文本 * @param mess */
    public native void sendMess(String mess);

    /** * 计算数值和 * @param a * @param b * @return */
    public native int plusNum(int a,int b);
}

  • 编写完成后,生成 .class 文件。

在 Myeclipse 中,Java 文件保存之后就自动生成  class 文件

eclipse中怎么找到编译后的class路径:

https://jingyan.baidu.com/article/8275fc869f6f0c46a03cf61c.html


生成 *.h 头文件

进入 cmd 命令行,使用上一步生成的 .class 文件,利用 jdk 的 javah 命令生成 *.h 头文件。

# javah
# -classpath :E:\JNI_Java_Pro\bin 为.class 文件所在的根路径
# .class 文件的完整路径为E:\JNI_Java_Pro\bin\com\daniel\JNI_Test.class
# -d : E:\tmp\JNI 输出 *.h 头文件的路径
# -jni : 生成JNI样式的包头文件,可以理解成 *.class 文件的 包路径+类名
# 
# 此处比较诡异的是,-classpath 必须得是*.class 的包路径文件的上一级;
# -jni 必须是*.class 文件的 包路径+类名,否则会报错。

javah -classpath E:\JNI_Java_Pro\bin -d E:\tmp\JNI -jni com.daniel.JNI_Test

最后会在执行命令的路径下面生成.h文件。


Java 通过 JNI 调用 C/C++ 类库

编写C++代码

  • 创建一个C++项目 
    Java 通过 JNI 调用 C/C++ 类库

  • 设置应用类型为 dll     
    Java 通过 JNI 调用 C/C++ 类库

  • 将 jdk 目录下的 jni.h 、 jni_md.h 以及之前生成的 com_daniel_JNI_Test.h 放入项目根路径下的 include 文件夹 (需自己创建文件夹) 
    Java 通过 JNI 调用 C/C++ 类库

  • 添加项目包含目录,将上一步创建的 include 文件夹包含进项目。 
    Java 通过 JNI 调用 C/C++ 类库

  • 创建 test_jni.cpp 文件,并编写 c++ 代码实现,其中的方法头,可以从 com_daniel_JNI_Test.h 中拷贝。 
    Java 通过 JNI 调用 C/C++ 类库

// JNI_gen.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#include "iostream"
#include "com_ning_C_ZCDemo_JNI_Test.h"

using namespace std;

// 注意格式:Test之前要加“1”,否则出错。原因暂时不知
JNIEXPORT void JNICALL Java_com_ning_C_ZCDemo_JNI_1Test_sendMess   
(JNIEnv *env, jobject obj, jstring str){
	char* t;
	t = (char*)env->GetStringUTFChars(str, 0);
	cout << t << endl;

}

JNIEXPORT jint JNICALL Java_com_ning_C_ZCDemo_JNI_1Test_plusNum
(JNIEnv *env, jobject obj, jint ia, jint ib){
	return ia + ib;

}


生成C++dll

运行C++项目的生成按钮,并在生成路径下找到生成的 dll 文件(本文为 jni_gen.dll)。

VS配置管理器https://blog.csdn.net/jing_xian/article/details/53306248   

 注意:“活动方案解决平台”设置为“X64”;  生成“Release”


Java调用C++ dll

将DLL文件复制到Java项目中某个目录,之后将这个目录配置进项目的(build path)Native library location

将生成的 *.dll 添加到Java项目的 Native Library 中,如使用Eclipse,如下图: 
Java 通过 JNI 调用 C/C++ 类库

修改最初的 JNI_Test.java 的代码,调用 dll 中的方法,可看到最下方输出的执行结果。 
Java 通过 JNI 调用 C/C++ 类库