文章目录
这个确实卡了我一段时间。
先说说必要性吧。
- java无法处理的操作(指向地址)
- 用其他语言会方便很多。
- 因为其他语言项目很成熟了,不好推掉重来。而我只习惯用java的话,便可以继续使用java工作,只是要调用人家写好的代码。
java调用除了C语言的其他语言都较容易,甚至可以靠导包来完成转换,唯独C难搞,盲猜是因为其可访问物理地址的缘故。
那么java如何调用c?
步骤如下:
1. idea创建一个java类
2. 通过命令生成.h文件
3. vs2015创建dll项目
4. 修改dll项目的属性
5. 补充dll项目的头文件和源文件
6. 生成dll文件
7. idea导入dll文件
8. idea使用函数
idea创建一个java类
严格来说,核心步骤并不是创建一个java类,而是创建一个方法,那个方法要被native修饰,这才是关键。
package cn.hsl.search;
public class javaConnectC {
public native void hsl(String a,char b,int c);
}
通过命令生成.h文件
操作步骤为:
- 找到第一步所创建的java文件
- 打开cmd
- 输入命令 javac -h ./ [java文件位置]
然后就会在cmd的当前路径下生成一个.h文件,我们把那个.h文件剪切到我们的临时目录里。结束了就可以把目录干掉
那个.h文件名就是我们的包名+类名
例如我的包名加 cn.hsl.search
类名叫javaConnectC
然后.h的文件名就是:cn_hsl_search_javaConnectC
其里面的方法在文件名的基础上,在最前面还要加个Java,最后面还要加上方法名
即:Java_cn_hsl_search_javaConnectC_hsl
vs2015创建dll项目
其实vs2019应该也行的,但我那时候不懂…
新建一个dll项目
把dll项目下的头文件和源文件目录下的文件都可以删了
我命名的dll项目名为javaConnectC,放的目录为桌面/JCC
修改dll项目的属性
右键单机dll项目,找到 属性选项(其实左键单机dll项目,然后alt+enter也可以直接打开)。
会弹出一个对话框,然后找到 配置属性 - VC++ 目录
然后添加VC++ 目录下的包含目录的值,点击包含目录的值,单击最右边的下拉按钮,选择《编辑》
然后选择本地jdk目录下include文件夹,我的是 D:/jdk-14.0.1/include
和选择jdk目录下的include/win32文件夹,我的是 D:/jdk-14.0.1/include/win32
感到难找的话,其实也可以全盘搜索jni.h文件,包含那个文件的jdk就是我们所需要的jdk
以上是VC++ 目录的修改
然后是预编译头的修改
还是那个属性对话框
找到 配置属性 - C/C++ - 预编译头
在预编译头那里找到预编译头的值,点开最右边的下拉按钮,选择不使用预编译头
然后就结束了。
补充dll项目的头文件和源文件
导入文件
找到通过命令生成的.h文件,我的是直接放在桌面的。
然后将.h文件复制到dll项目的目录下。即,将 临时目录/javaConnectC.h 复制到 桌面/JCC/javaConnectC/javaConnectC 目录下,反正就是放在原来存放dll项目头文件的位置。
我们再创建一个.c/.cpp文件,如果已经有了,可以也放在原来dll项目的头文件的位置,即桌面/JCC/javaConnectC/javaConnectC 下。
然后去vs的dll项目那里,在头文件和源文件目录那里进行导入头、源文件。
源文件的制作
我的源文件名叫javaConnectC.c文件,其实cpp也行,而且也不必跟.h文件同名
只是对源文件内容有要求,必须导入那个生成的.h文件,即javaConnectC.h文件
然后方法的话,复制.h文件下的 JNIEXPORT所修饰的那段方法。
复制到.c文件那里,然后给方法的形参加上字段。
然后把那个方法当作是main方法,就可以当作是C文件去敲了。
至于传值情况下,貌似传值若是char类的话,便不可用printf去打印char字符。其他String和int都可以
头文件代码:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class cn_hsl_search_javaConnectC */
#ifndef _Included_cn_hsl_search_javaConnectC
#define _Included_cn_hsl_search_javaConnectC
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: cn_hsl_search_javaConnectC
* Method: hsl
* Signature: (Ljava/lang/String;CI)V
*/
JNIEXPORT void JNICALL Java_cn_hsl_search_javaConnectC_hsl
(JNIEnv *, jobject, jstring, jchar, jint);
#ifdef __cplusplus
}
#endif
#endif
源文件代码:
#include"cn_hsl_search_javaConnectC.h"
#include"stdio.h"
JNIEXPORT void JNICALL Java_cn_hsl_search_javaConnectC_hsl
(JNIEnv * env, jobject obj, jstring str, jchar chr, jint jin) {
putchar(chr);
printf("this is int: %d\n",jin);
printf("this is string: %s\n", str);
}
生成dll文件
接下来直接按 生成 -> 生成xxx项目 即可
idea导入dll文件
将dll文件放到idea的lib的位置
的位置:找个跑的通的代码,加个静态代码 static{ System.loadLibrary(“aaa”) },然后就会报错,提示我们[lib的位置]上没有这个aaa.dll
其实也可以自己声明一个lib的位置,但我不会做。
idea使用函数
随便找个跑的通的位置,调用第一步创建的那个java类
然后在类下面搞个静态代码块,来提前加载lib
static{
System.loadLibrary("javaConnectC");
}
然后就可以在这个类里面直接调用java的那个方法。
package cn.hsl.search;
import cn.hsl.dao.mapper.GoodsMapper;
import cn.hsl.dao.pojo.Goods;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class SearchApplicationTest {
static {
System.loadLibrary("javaConnectC");
}
@Test
void ww(){
javaConnectC javaConnectC = new javaConnectC();
javaConnectC.hsl("HSL",'i',1);
}
}
参考了两个作者的步骤
参考 PacosonSWJTU 从创建java类到创建.h文件
参考 你是小KS 怎么将.h文件直接制作成dll
最后我自己摸索了怎么在idea导入dll
至于使用嘛,也是参考了 PacosonSWJTU
PacosonSWJTU 博客网址:https://blog.youkuaiyun.com/PacosonSWJTU/article/details/50618022
PacosonSWJTU 博客标题:本地方法(JNI)——从java 程序中调用C函数
你是小KS 博客网址:https://blog.youkuaiyun.com/weixin_45492007/article/details/123018918
你是小KS 博客标题:Java:使用javah生成.h文件并完成dll调用
谢幕