JNI概念
JNI (Java Native Interface) 是 Java 平台的一个关键组件,它允许 Java 代码调用本地应用程序或库中的函数(通常是 C 或 C++ 代码),同时也允许本地代码调用 Java 方法。JNI 为 Java 和本地代码之间的交互提供了一个桥梁,使得开发者可以在 Java 应用程序中利用本地代码的强大功能,例如高性能计算、设备驱动程序访问等。
JNI 的用途
- 性能优化:对于计算密集型任务,使用 C 或 C++ 编写的本地代码通常比纯 Java 代码更快。
- 硬件访问:有些硬件设备只能通过本地代码访问,JNI 提供了一种途径来实现这种访问。
- 跨语言集成:JNI 使得 Java 代码可以调用其他语言编写的库,反之亦然。
JNI 的工作流程
1.编写java测试类
2.利用java测试类生成C头文件
3.利用C头文件编写C代码
4.生成C库
5.java调用测试
第一步:编写java测试类
没有java基础,在ubuntu下用java相关命令简单写了个类,以下附有代码和执行命令。
代码如下:
java
package com.aijiao.test;
public class JNIDemo {
//定义一个方法,该方法在C中实现
public native String testHello();
public static void main(String[] args){
//加载C文件
System.loadLibrary("TestJNI2");
JNIDemo jniDemo = new JNIDemo();
System.out.println(jniDemo.testHello());
}
}
第二步:利用java测试类生成C头文件
生成命令如下:
javah -classpath . -jni com.aijiao.test.JNIDemo
该命令需要在java测试类的工程的bin目录下执行,这里没有新建工程,不存在bin目录,用javah执行总是出错,最后照着别人生成的头文件改了下,发现也可以用,头文件大致长这样:
java
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class com_aijiao_test_JNIDemo */
//避免重复包含头文件
#ifndef _Included_com_aijiao_test_JNIDemo
#define _Included_com_aijiao_test_JNIDemo
//c++编译环境中才会定义__cplusplus (plus就是"+"的意思
#ifdef __cplusplus
extern "C" { //告诉编译器下面的函数是c语言函数(因为c++和c语言对函数的编译转换不一样,主要是c++中存在重载)
#endif
/*
* Class: com_aijiao_test_JNIDemo
* Method: displayHelloJni
* Signature: ()V
*/
JNIEXPORT jstring JNICALL Java_com_aijiao_test_JNIDemo_testHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
其实这个头文件不是必须的
第三步:利用C头文件编写C代码
有用javah生成头文件对应的c代码
cpp
#include "com_aijiao_test_JNIDemo.h"
#include <iostream>
#include <stdio.h>
JNIEXPORT jstring JNICALL Java_com_aijiao_test_JNIDemo_testHello
(JNIEnv * env, jobject obj) {
//printf("this is C++ print");
return env->NewStringUTF("set value success");
}
没有用javah生成头文件对应的c代码
cpp
#include "jni.h"
#include <iostream>
#include <stdio.h>
extern "C"
JNIEXPORT jstring JNICALL Java_com_aijiao_test_JNIDemo_testHello
(JNIEnv * env, jobject obj) {
//printf("this is C++ print");
return env->NewStringUTF("set value success");
}
两个略有差异,主要是要把extern "C"带上,不然会链接不到函数
第四步:生成C库
先拷贝两个头文件(jni.h和jni_md.h)过来再生成.so文件。jni.h和jni_md.h都在jdk目录下有,直接用find命令找需要拷贝到cpp文件夹下
g++ TestJNI.cpp -fPIC -shared -o libTestJNI2.so
第五步:java调用测试
整个测试工程文件层级如下:
以下java命令都是在java文件夹下执行的:
根据.java文件生成.class文件:javac -d . JNIDemo.java
执行class文件:java com.aijiao.test.JNIDemo
指定libTestJNI2.so文件的路径,把.so路径加入环境变量:export LD_LIBRARY_PATH=/home/lxj/myproject/testJNI2/cpp:$LD_LIBRARY_PATH,不然会加载不上库会报错
参考菜鸟教程:JNI 入门教程 | 菜鸟教程 (runoob.com),也有自己踩得坑,欢迎大家评论,有交流才会有进步