Java-JNI调用dll动态链接库

众所周知,python调用dll动态链接库极其简单,加载一下dll文件,就可以调用其中的方法。那么目前仍热火朝天的Java能不能调用dll库,使用其中的方法呢?当然是可以的,但是相对于python来讲是稍微有一点困难。

那么Java是怎么调用dll动态链接库的呢?

大概分为以下几步:

1.创建Java类,在该类中加载dll文件,再用该类生成xxx.h文件

2.创建xxx.c文件,引用xxx.h头,实现xxx.h中的方法。

还有信心继续下去嘛?听着有点头大?又是h文件又是头文件的,糟心!别慌,准备一包瓜子咱们来调用dll中的一个实战一波你就明白了,下边我们实现一个Java调用dll中方法,实现两个数相加并返回控制台输出的简单案例。

1、先创建Java类,我这里创建了一个ConnectDll类(包名我也复制下来了)。

package com.csdn.dll;

public class ConnectDll {
    static {
        System.loadLibrary("");
    }
    public static native int add(int num1,int num2);
}

2.编译此类,生成对应的.class文件。

什么?不会生成?请自行百度javac命令。

3.将.class文件编译成 .h头文件。

很多人到这里就懵了,java文件还能转成.h文件么?是的,利用javah命令,可以将class字节码文件转换成.h文件。

众所周知,我们写项目,一般会在src下写很多级包名,然后在包里边写各个类,从上面的代码可以看出,我的包名为com.csdn.dll。但是我们生成项目文件的时候,系统会自动地把包名转换成各级文件夹。如果用javac命令将.java文件编译成class文件,需要进入到java文件所在的文件夹,但是用javah命令,只需要到包的上一级,即src目录下即可。然后用javah命令 +包名+类名。

具体命令: javah com.csdn.dll.ConnectDll  (因为ConnectDll类的包名是com.csdn.dll)。

生成的.h文件就在src目录下。

4.让我们一窥.h文件的究竟。

学过C语言的都知道h是头文件,所以我认为h文件相当于Java的接口,C文件相当于java的实现类。(由于我C语言比较差,这里可能不太准确,如有大佬看到,请及时评论纠正。),下面是h文件中的东西,让我们一起看看。

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

#ifndef _Included_com_csdn_dll_ConnectDll
#define _Included_com_csdn_dll_ConnectDll
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_csdn_dll_ConnectDll
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_csdn_dll_ConnectDll_add
  (JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

 

从这个头文件中我们可以看到存在这样一个方法

JNIEXPORT jint JNICALL Java_com_csdn_dll_ConnectDll_add(JNIEnv *, jclass, jint, jint);

对比一下我们在ConnectDll类中写的方法

public static native int add(int num1,int num2);

我们可以发现一些东西还是比较相似的。如:jint   ----->>int。

5.编写对应的实现文件C文件,生成dll库。

到了这里,我不知道大家是否还记得我们的初衷?我们的初衷是想用java调用dll文件,但是我们写了半天了也没见dll文件的生成以及调用啊?(之前接触过C的大佬可能知道,但是对于C语言本身就不怎么样的我来说,生成dll难为了我半天。)

以下内容C语言大佬可以自动忽略

如何生成dll文件?

我这里的工具是DevC++。(觉得Dev麻烦的可以忽略,然后自行百度其他软件生成dll)

1.打开Dev,文件->新建->项目,选择DLL项目,C语言,项目名称。

2.创建完项目,如下

3.将h和C文件书写完整保存,编译一下,就能在该项目目录中找到dll文件。

根据java生成的h文件,生成dll库并调用其中方法。

我们知道了如何生成dll文件,但是这跟我们java生成的.h文件又有什么关系呢?通过上面我们可以看到dll动态链接库实际上就是.h和.c编译链接生成的,我们通过dll文件可以调用dll中实现的方法。还是很混乱对吧,别急,我们先做,做完再回过头来看。

我们通过javah生成了.h文件,将生成的.h文件复制到这个项目中,并写对应的.c文件。H文件内容上边已给,C文件如下,

注意我这里引用的h文件是dll.h,我是把生成的h文件的内容复制到了dll.h下,文件内容如下:

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

#ifndef _Included_com_csdn_dll_ConnectDll
#define _Included_com_csdn_dll_ConnectDll
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_csdn_dll_ConnectDll
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_csdn_dll_ConnectDll_add
  (JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

这是C文件,文件内容如下

/* Replace "dll.h" with the name of your header */
#include "dll.h"
#include <windows.h>

JNIEXPORT jint JNICALL Java_com_csdn_dll_ConnectDll_add(JNIEnv * env, jclass cls, jint i, jint j){
	return i+j;
} 

点击编译,一般是会报错的,原因是没有 <jni.h>头文件。自行百度解决。

编译完成后,发现dll项目文件中多了一个后缀为.dll文件。这个就是我们要的。

6.Java文件加载Dll文件

在我们最开始的ConnectDll类中,有这么一段代码,System.loadLibrary("");这就是加载dll文件的代码,修改成这样System.loadLibrary("ConnectDll");(因为我的dll文件是ConnectDll.dll。)

7.编写Java测试类调用此方法

package com.csdn.test;

import com.csdn.dll.ConnectDll;

public class Test {
    public static void main(String[] args) {
        System.out.println(ConnectDll.add(3,5));

    }
}

运行,会出现一堆错误,是因为你系统找不到你说的这个dll文件,怎么办呢?把这个dll文件放入JDK/bin目录中可以解决。

但是我们不能只知其然不知其所以然,System.loadLibrary("");这行代码的意思就是加载文件,但是它加载的是环境变量下的文件,系统会查找环境变量下有没有这个文件。当然加载文件还有一个方法System.load("");这个方法是加载绝对路径的文件。

8.综上所述

1.创建Java类

2.编译生成h头文件

3.实现头文件中的方法并生成dll

4.设置Java类中文件加载地址

9.展望

我们是Java开发者,我们不太可能会自己直接编写dll文件,一般都是调用别人写好的dll文件。我们可以自己编写一个dll文件来调用别人写好的dll,但是无论怎样都太过繁琐。我们程序员应该有一种精神叫"懒",我们接受不了这种太过复杂的调用,这样开发太过于繁琐。所以我们应该想着有没有什么简单的方式,可以直接在java中调用,像python那样。在写此文章的时候,搜到了其他解决方案,JNA和JNative,可以简化开发。

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值