JNI简单学习(java调用C/C++)

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);
	}
}

运行结果:

相关推荐
黎雁·泠崖2 小时前
【魔法森林冒险】1/14 项目总览:用Java打造你的第一个回合制冒险游戏
java·开发语言
NuageL2 小时前
原始Json字符串转化为Java对象列表/把中文键名变成英文键名
java·spring boot·json
C++ 老炮儿的技术栈2 小时前
Qt 编写 TcpClient 程序 详细步骤
c语言·开发语言·数据库·c++·qt·算法
222you3 小时前
Redis的主从复制和哨兵机制
java·开发语言
江湖有缘3 小时前
零基础入门:使用 Docker 快速部署 Organizr 个人主页
java·服务器·docker
chilavert3183 小时前
技术演进中的开发沉思-357:重排序(下)
java·后端
Boop_wu3 小时前
Spring生态
java·后端·spring
jzheng86103 小时前
Spring Boot(快速上手)
java·spring boot·后端
wgslucky3 小时前
SpringBoot解决Request和Response的内容多次读取的问题
java·spring boot·多次读取request数据
wangjialelele3 小时前
Linux下的IO操作以及ext系列文件系统
linux·运维·服务器·c语言·c++·个人开发