主要参考了这篇文章:原文链接
一、软件环境
硬件:树莓派CM4
操作系统:官方64位
编译工具:g++
JDK:11
二、过程
- java代码中声明带有native修饰的类方法,该native方法只是在java中进行声明,而不进行实现,在需要调用navtive方法之前进行system.loadLibrary(“xxx”),然后通过类调用方法xxx即可
- 使用javah从java的class文件生成与native函数相应的头文件
- 通过引用含有native方法声明的头文件,采用C++编写native方法的实现,并将其编译为动态链接库
- 对java编译并执行即可
- 据说jdk8及以前用javah,以后用javac -h
三、java部分
1、在linux目录编写java代码
nano /home/hellozous/c/com/zouston/TestJNI.java
package com.zouston;
/**
* 描述:测试JNI
* 日期: 2022-07-06
* 时间: 14:11
*
* @author: K.L.Zous
*/
public class TestJNI
{
/**
* 声明本地库中的函数
*/
public native void helloWorld();
public static void main(String[] args)
{
//载入本地库
System.loadLibrary("TestJNI");
TestJNI t = new TestJNI();
//调用本地库中的函数
t.helloWorld();
}
}
2、生成头文件
javac -h ./ /home/hellozous/c/com/zouston/TestJNI.java
此时生成了com_zouston_TestJNI.h
其中包含如下内容,作为C++中的方法名
JNIEXPORT void JNICALL Java_com_zouston_TestJNI_helloWorld
三、C++部分
1、创建CPP文件
nano /home/hellozous/c/com/zouston/helloWorld.cpp
#include "com_zouston_TestJNI.h"
#include <iostream>
JNIEXPORT void JNICALL Java_com_zouston_TestJNI_helloWorld(JNIEnv *env, jobject obj)
{
std::cout << "Hello world!" << std::endl;
}
2、生成so
g++ -fPIC -shared -o libTestJNI.so -I /usr/lib/jvm/java-11-openjdk-arm64/include -I /usr/lib/jvm/java-11-openjdk-arm64/include/linux/ helloWorld.cpp
- -fPIC选项使编译器在编译阶段生成与位置无关的代码,以使共享库能够在内存中被正确加载,PIC即Position, Independent Code。使用-shared选项时必须有该选项,否则编译期会出错
- -shared编译器生成共享链接库
- -o后面的动态链接库的命名规则必须与linux下的动态链接库一致,即libxxx.so的形式
- -I后面跟的是jni所需要的头文件路径
3、运行
cd /home/hellozous/c
java -Djava.library.path=. com.zouston.TestJNI