Java的JNI机制
Java还有一个JNI机制,它的全称:Java Native Interface,即Java本地接口。它允许在Java虚拟机内运行的Java代码与其他编程语言(如C/C++和汇编语言)编写的程序和库进行交互(在Android开发中用得比较多)
简单举例:我们现在想要让C++语言程序帮助我们的Java程序实现a+b的运算,首先我们需要创建一个本地方法:
package com.test;
public class Main {
public static void main(String[] args) {
System.out.println(sum(1,2));
}
//native 是本地方法关键字,无需在Java中实现本方法
public static native int sum(int a,int b);
}
创建好后,接着点击构建按钮,会出现一个out文件夹,也就是生成的class文件在其中
接着我们直接生成对应的C头文件:
(注意,这条指令基于jdk1.8实现,jdk版本过高 请使用javac -h指令)
javah -classpath out/production/pro02 -d ./jni com.test.Main
生成的头文件位于jni文件夹下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_test_Main */
#ifndef _Included_com_test_Main
#define _Included_com_test_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_test_Main
* Method: sum
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_com_test_Main_sum
//这里的两个jint就是传入的a,b两个参数
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
接着我们在CLion中新建一个C++项目,引入刚刚生成的头文件并导入jni相关头文件(在JDK文件夹中)
首先修改CMake文件:
cmake_minimum_required(VERSION 3.20)
project(pro02)
#和使用的jdk的路径有关
include_directories(E:/Users/19318/.jdks/corretto-1.8.0_322-1/include)
include_directories(E:/Users/19318/.jdks/corretto-1.8.0_322-1/include/win32)
include_directories(E:/Users/19318/.jdks/corretto-1.8.0_322-1/include/win32/bridge)
set(CMAKE_CXX_STANDARD 14)
#add_executable:生成一个可执行文件 不添加则无法再clion中运行
add_executable(pro02 com_test_Main.cpp com_test_Main.h)
#add_library:生成一个库
#sum:是生成共享库的名字,前面会自动加上lib前缀,如这里windows生成的是 libsum.dll
#SHARED:库的类型为动态,windows上生成.dll,而STATIC 则是生成静态库,windows生成.a文件
add_library(sum SHARED com_test_Main.cpp)
再将jni下的头文件复制到c++项目下:
认识一下引用类型对照表:
接下来可以开始编写程序了:
#include <jni.h>
#include "com_test_Main.h"
JNIEXPORT jint JNICALL Java_com_test_Main_sum
(JNIEnv *, jclass, jint a, jint b)
{
return a+b;
}
接着我们就可以将cpp编译为动态链接库,在Windows下应该生成.dll文件
直接运行项目,我们可以在cmake-build-debug文件夹下找到生成的dll文件
注意这里运行时会报错undefined reference to 'WinMain',因为我们的项目没有main函数,但报错并不影响dll文件的生成和使用。
将生成的dll文件加载到Java程序中,运行即可得到结果。
public class Main {
static {
//输入dll文件的路径
System.load("D:\\C++\\pro02\\cmake-build-debug\\libsum.dll");
}
public static void main(String[] args) {
System.out.println(sum(1,2));
}
public static native int sum(int a,int b);
}