JNI
JNI(Java Native Interface)是 JDK 内置的标准原生接口,是 Java 平台与 C/C++ 等原生代码(Native Code)交互的底层规范,允许 Java 虚拟机(JVM)中的 Java 代码调用原生代码,也支持原生代码回调 Java 代码。与 JNA(基于 JNI 封装的上层类库)不同,JNI 是 Java 与原生代码通信的 "底层基础",所有 Java 调用原生库的方案(包括 JNA、JNR 等)最终都基于 JNI 实现。
核心组件
| 组件 | 作用 |
|---|---|
| jni.h | 核心头文件,定义 JNI 的类型、函数、宏(如JNIEnv、jobject、FindClass); |
| JNIEnv* | 核心指针,提供 JNI 函数调用接口(如创建 Java 对象、调用 Java 方法、类型转换),线程私有; |
| JavaVM* | Java 虚拟机实例指针,用于跨线程 / 跨进程获取JNIEnv,全局唯一; |
关键类型映射(Java 对应 C/C++)
| Java 类型 | JNI 类型 | C/C++ 类型 |
|---|---|---|
| byte | jbyte | signed char |
| short | jshort | short |
| int | jint | int |
| long | jlong | long long(8 字节) |
| float | jfloat | float |
| double | jdouble | double |
| boolean | jboolean | unsigned char |
| char | jchar | unsigned short |
| String | jstring | 无直接映射(需通过 JNI 函数转换为 char*) |
| Object | jobject | 无直接映射(指向 Java 对象的指针) |
| 数组 | jarray/ jintArray/ jbyteArray | 对应数组类型指针 |
演示
演示环境:
开发环境为:idea、visual studio
java版本:jdk-17.0.15
c++:ISO C++14 标准 (/std:c++14)
x64环境下
1.创建Java 类
创建一个名为JavaCode的maven项目
声明native方法
python
public class NativeFunction
{
public native int add(int a, int b);
}
2.生成 JNI 头文件
通过Java 命令行生成包含方法签名的 C/C++ 头文件;
javac -h jni NativeFunction.java
执行完以上命令后,会生成一个jni文件夹,里面的org_example_NativeFunction.h文件就是c/c++的头文件

3.编写 C/C++ 实现
创建一个名为CPPCode的空项目
将生成的头文件(org_example_NativeFunction.h)移动到头文件夹下

此时头文件(org_example_NativeFunction.h)里面会报错,在windows环境中需要引入2个头文件,分别为:
jni.h
jni_md.h
这两个文件在java文件夹里面,比如下面这两个路径:
D:\Program Files (x86)\java\jdk-17.0.15\include
D:\Program Files (x86)\java\jdk-17.0.15\include\win32
点击项目属性,将上面2个路径放进附加包含目录里面

补充:如果没有C/C++选项有可能是没创建C/C++文件导致的,创建了就好了(提前创建NativeFunction.cpp文件)

实现头文件(org_example_NativeFunction.h)中声明的原生方法
创建NativeFunction.cpp文件
cpp
//引入头文件
#include "org_example_NativeFunction.h"
//实现方法,将需要使用的参数设置名称a,b
JNIEXPORT jint JNICALL Java_org_example_NativeFunction_add(JNIEnv*, jobject, jint a, jint b)
{
return a + b;
}
4.编译动态库
根据自己的平台配置
项目属性设置为:
配置类型设置为:动态库

生成解决方案:
我的是x64环境

然后点击生成解决方案
在项目的 \x64\Debug 目录下会生成ddl文件

5.Java加载动态库
将编译好的dll动态库放进资源文件夹下:

编写加载动态库的代码,Java 加载动态库并调用 native 方法。
java
public class Main
{
static
{
//加载动态库
String dllPath = System.getProperty("user.dir")+"\\src\\main\\resources\\CPPCode.dll";
//不支持classpath
System.load(dllPath);
}
public static void main(String[] args)
{
//创建NativeFunction对象
NativeFunction nativeFunction = new NativeFunction();
//调用add方法
int result = nativeFunction.add(5, 6);
System.out.println("add(5, 6) = "+result);
}
}
运行结果:
