JNI入门实践

JNI 全称 Java Native Interface。Java本地方法接口,它是Java语言允许Java代码与C、C++代码交互的标准机制。维基百科是这样解释的:“当应用无法完全用Java编程语言实现的时候,(例如,标准Java类库不支持的特定平台特性或者程序库时),JNI使得编程者能够编写native方法来处理这种情况”。这就意味着,在一个Java应用程序中,我们可以使用我们需要的C++类库,并且直接与Java代码交互,而且在可以被调用的C++程序内,反过来调用Java方法(回调函数)。

JNI的优势

  • 操作系统相关 JNI使得一些"过程"无需在Java中实现。例如,硬件敏感的,或者直接与操作系统API关联的命令。
  • 性能优化 底层的库,如图形,计算,各种类型的渲染等等,可以提高应用的运行性能。
  • 既有实现 已经有大量的库已经被实现,编程者可直接使用,不用再自行编写。这里的库指的是用其他编程语言实现的程序库,例如IO流或者线程等底层与OS交互的操作都是由C/C++实现的。

JNI的实现

1、定义Java类

定义一个带native方法的java类如:

/**
 * @author jack
 */
public class JniCompileTest {
    /**
     * 执行jni调用
     */
    public native Map excute(String param1, Object param2);
}
2、生成头文件

在项目的根目录下执行javah命令

javah -classpath . -jni com.package.jni.test.JniCompileTest

完成后,会在根目录下生成一个同名的.h结尾的头文件。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class com_package_jni_test_JniCompileTest */

#ifndef _Included_com_package_jni_test_JniCompileTest
#define _Included_com_package_jni_test_JniCompileTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_package_jni_test_JniCompileTest
 * Method:    excute
 * Signature: (Ljava/lang/String;Ljava/lang/Object;)Ljava/util/Map;
 */
JNIEXPORT jobject JNICALL Java_com_package_jni_test_JniCompileTest_excute
  (JNIEnv *, jobject, jstring, jobject);
#ifdef __cplusplus
}
#endif
#endif
3、引入头文件

在头文件中的 jni.h 如果在编译动态链接库(.so文件)的时候找不到,可以去本地的JDK目录中的include文件下找到两个文件:jni.hjni_md.h 。然后拷贝到与JniCompileTest.h同目录下。

修改引入方式

#include  

改为

#include "jni.h" 

然后可以定义一个同名的cpp源码文件,开发JNI的cpp实现了

//
// Created by jack on 2021/7/10.
//
#include "com_package_jni_test_JniCompileTest.h"

JNIEXPORT jobject JNICALL Java_com_package_jni_test_JniCompileTest_excute
        (JNIEnv *env, jobject, jstring, jobject){
    // do something
    return NULL;
}
4、编译动态链接库

在clion中构建一个cmake项目,然后写CMakeLists.txt

project(JniCompileTest C CXX)
cmake_minimum_required(VERSION 2.8.0)
# 这里用自己的目录即可
INCLUDE_DIRECTORIES(src/main/cpp/jnilib/include/)

FILE(GLOB SRC_JNI_LIBRARY src/main/cpp/jnilib/src/*.cpp)
FILE(GLOB HEADER_JNI_LIBRARY src/main/cpp/jnilib/include/*.h)

add_library(JniCompileTest SHARED ${HEADER_JNI_LIBRARY} ${LIST_SRC} ${SRC_JNI_LIBRARY})

完成后执行编译

5、java引入动态链接库

java 使用动态库,需要用System类load,例如在上面的类的构造方法的中加入即可。

/**
 * @author jack
 */
public class JniCompileTest {
    public JniCompileTest(){
        // mac下文件为JniCompileTest.dylib
        File outputJNIFile = new File("/user/jack/JniCompileTest.so");
        System.load(outputJNIFile.getAbsolutePath());
    }
    /**
     * 执行jni调用
     */
    public native Map excute(String param1, Object param2);
}

结尾

JNI的封装完成,但是在JNI的开发中,还是不少注意的地方,例如JNI对象的定义,如何解析java传递来的对象,如果回调java方法等。

你可能感兴趣的:(JNI入门实践)