简介
- 本节示例怎么使 Java应用程序 通过 JNI 调用 C语言 输出
Hello World!
。
流程
- 创建一个
HelloWorld.java
文件并声明原生方法。
- 使用 javac 编译
HelloWorld.java
,生成HelloWorld.class
文件。
- 使用 javah 生成C头文件
HelloWorld.h
,该头文件包含了原生函数实现的原型。
- 新建文件
HelloWorld.c
并按照HelloWorld.h
中声明的原生函数原型实现原生代码。
- 将
HelloWorld.c
构建成为一个原生库,生成HelloWorld.dll
或者HelloWorld.so
。
- 使用 Java 运行HelloWorld程序,
HelloWorld.class
和HelloWorld.dll/so
会在运行时被加载。
HelloWorld示例
1. 创建HelloWorld.java
代码
public class HelloWorld {
static {
// "HelloWorld" 表明载入HelloWorld.dll
System.loadLibrary("HelloWorld");
}
public static void main(String[] args) {
new HelloWorld().print();
}
private native void print();
}
解说
- 上述代码主要包含三个部分:
- 一个静态代码块,用来加载 动态链接库 。
- 一个主函数作为 Java应用程序 入口,并在主函数中调用
print
。
- 一个原生函数
print
的声明,由原生代码实现。
- 包含原生代码的 动态链接库 一定要提前加载。
-
print
函数声明中的native
修饰符表示该函数是使用其他语言实现的。
2. 生成HelloWorld.class
3. 使用CLion创建C/C++项目
- 保证 CLion 使用的是 MinGW-w64 而不是 MinGW-32 。
- 设置
JAVAHOME
环境变量,指向 jdk 目录。
- 通过
CMakeList.txt
设置 JNI 包含目录。
- 通过
CMakeList.txt
设置构建完毕后自动复制 DLL 到 Java 项目目录下。
-
CMakeList.txt
文件参考,
cmake_minimum_required(VERSION 3.7)
project(JNI_c)
set(CMAKE_C_STANDARD 11)
# 相当于 SOURCE_FILES = "HelloWorld.h HelloWorld.c"
set(SOURCE_FILES HelloWorld.h HelloWorld.c)
add_library(JNI_c SHARED ${SOURCE_FILES})
include_directories($ENV{JAVAHOME}/include)
include_directories($ENV{JAVAHOME}/include/win32)
# 设置输出DLL的名字前缀
set_target_properties(JNI_c PROPERTIES PREFIX "")
# 设置输出DLL的名字,此处输出HelloWorld.dll
set_target_properties(JNI_c PROPERTIES OUTPUT_NAME "HelloWorld")
# 构建完后复制DLL到指定目录
add_custom_command(TARGET JNI_c POST_BUILD # JNI_c是项目名称
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_FILE_DIR:JNI_c>/HelloWorld.dll" # input dir
"C:/ProgramProjects/Java/JNI") # output dir
4. 生成HelloWorld.h
1. 配置 IDEA 中生成头文件规则(已配置则跳过)
- File -> Settings -> External Tools。
- 点击 “+” 按钮。
-
Name :
生成头文件
。
-
Group :
JNI
。
-
Options : 全部勾选。
-
Show in : 全部勾选。
-
Program :
$JDKPath$\bin\javah.exe
。
-
Parameters :
-jni -v -d $FileDir$ $FileClass$
。$FileDir$
表示输出目录,将$FileDir$
设置为 CLion 项目目录。
-
Working directory :
$SourcepathEntry$
。
- 点击确定。
2. 生成
- 选择对应的java文件。
- 右键 -> JNI -> Generate Header File。
- 在
$FileDir$
对应的目录里生成了HelloWorld.h
。
3. 解说HelloWorld.h文件
代码
/*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv * , jobject);
解说
- 注释部分:
-
Class :函数来自的那一个类的名字。
-
Method :这个函数的名字。
-
Signature :这个函数的签名。
-
()V
:函数的签名为void ()
。
-
(IFC)D
:这个函数的double (int, float, char)
。
- 代码部分:
-
void
:原方法的返回值。
-
JNIEnv *
:一个JNIEnv
接口指针。
-
jobject
:HelloWorld
对象本身,有点像 C++ 中的this
指针。
5. 实现HelloWorld.c
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv * env, jobject obj) {
printf("Hello World!\n");
}
#ifdef __cplusplus
}
#endif
5. 生成动态链接库并运行
- 在 Clion 中构建项目,生成 DLL 到对应目录。
- 设置 IDEA 中的 Run/Debug Configurations :
- 将 VM Options 设置为
-Djava.library.path=C:\ProgramProjects\Java\JNI\
- 运行程序。