JNI 全稱 Java Native Interface义矛。Java本地方法接口份氧,它是Java語言允許Java代碼與C存崖、C++代碼交互的標(biāo)準機制静暂。維基百科是這樣解釋的:“當(dāng)應(yīng)用無法完全用Java編程語言實現(xiàn)的時候,(例如晦毙,標(biāo)準Java類庫不支持的特定平臺特性或者程序庫時)生巡,JNI使得編程者能夠編寫native方法來處理這種情況”。這就意味著见妒,在一個Java應(yīng)用程序中孤荣,我們可以使用我們需要的C++類庫,并且直接與Java代碼交互须揣,而且在可以被調(diào)用的C++程序內(nèi)垃环,反過來調(diào)用Java方法(回調(diào)函數(shù))。
JNI的優(yōu)勢
- 操作系統(tǒng)相關(guān) JNI使得一些"過程"無需在Java中實現(xiàn)返敬。例如,硬件敏感的寥院,或者直接與操作系統(tǒng)API關(guān)聯(lián)的命令劲赠。
- 性能優(yōu)化 底層的庫,如圖形秸谢,計算凛澎,各種類型的渲染等等,可以提高應(yīng)用的運行性能估蹄。
- 既有實現(xiàn) 已經(jīng)有大量的庫已經(jīng)被實現(xiàn)塑煎,編程者可直接使用,不用再自行編寫臭蚁。這里的庫指的是用其他編程語言實現(xiàn)的程序庫最铁,例如IO流或者線程等底層與OS交互的操作都是由C/C++實現(xiàn)的讯赏。
JNI的實現(xiàn)
1、定義Java類
定義一個帶native方法的java類如:
/**
* @author jack
*/
public class JniCompileTest {
/**
* 執(zhí)行jni調(diào)用
*/
public native Map<String, String> excute(String param1, Object param2);
}
2冷尉、生成頭文件
在項目的根目錄下執(zhí)行javah命令
javah -classpath . -jni com.package.jni.test.JniCompileTest
完成后漱挎,會在根目錄下生成一個同名的.h結(jié)尾的頭文件。
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* 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 如果在編譯動態(tài)鏈接庫(.so文件)的時候找不到磕谅,可以去本地的JDK目錄中的include文件下找到兩個文件:jni.h和jni_md.h 。然后拷貝到與JniCompileTest.h同目錄下雾棺。
修改引入方式
#include <jni.h>
改為
#include "jni.h"
然后可以定義一個同名的cpp源碼文件膊夹,開發(fā)JNI的cpp實現(xiàn)了
//
// 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、編譯動態(tài)鏈接庫
在clion中構(gòu)建一個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})
完成后執(zhí)行編譯
5放刨、java引入動態(tài)鏈接庫
java 使用動態(tài)庫,需要用System類load嘉栓,例如在上面的類的構(gòu)造方法的中加入即可宏榕。
/**
* @author jack
*/
public class JniCompileTest {
public JniCompileTest(){
// mac下文件為JniCompileTest.dylib
File outputJNIFile = new File("/user/jack/JniCompileTest.so");
System.load(outputJNIFile.getAbsolutePath());
}
/**
* 執(zhí)行jni調(diào)用
*/
public native Map<String, String> excute(String param1, Object param2);
}
結(jié)尾
JNI的封裝完成,但是在JNI的開發(fā)中侵佃,還是不少注意的地方麻昼,例如JNI對象的定義,如何解析java傳遞來的對象馋辈,如果回調(diào)java方法等抚芦。