天天看點

JNI 簡介、基本原理

     jni是java native interface的縮寫,中文為java本地調用。從java1.1開始,java native interface(jni)标準成為平台的一部分,它允許java代碼和其他語言寫的代碼進行互動。jni一開始是為了本地已編譯語言,尤其是c和c++而設計的,但是它并不妨礙你使用其他語言,隻要調用約定受支援就可以了。

      使用與本地已編譯的代碼互動,通常會喪失平台可移植性。但是,有些情況這樣做是可以接受的,甚至是必須的。例如,使用一些舊的庫,與硬體、進行互動,或者為了提高程式的性能。jni标準至少保證能工作在任何java 實作下。

标準的類庫可能不支援你的程式所需的特性。或許你已經有了一個用其他語言寫成的庫或程式,而你希望在程式中使用它。

你可能需要用底層語言實作一個小型的時間敏感代碼,比如彙編,然後在你的程式中調用這些功能。

      以下是具體步驟:

 編寫帶有native聲明的方法的類

·使用指令編譯所編寫的java類,然後使用javah + java類名生成擴充名為h的頭檔案

·使用c/c++實作本地方法

·将c/c++編寫的檔案生成

·完成

示例:

helloworld.java:

package com.magc.jni;

      public class helloworld {

    static {

        system.loadlibrary("hello");

    }

    public     native void displayhello();

    /**

     * @param args

     */

    public static void main(string[] args) {

        new helloworld().displayhello();

}

進入src目錄下,編譯該java類,

指令:javac ./com/magc/jni/helloworld.java

在該helloworld.java所在目錄下生成helloworld.class

然後使用javah生成頭檔案,

指令:javah -jni com.magc.jni.helloworld

在目前目錄下生成com_magc_jni_helloworld.h頭檔案,此檔案供c、c++程式來引用并實作其中的函數

       helloworld.h:

/* do not edit this file - it is machine generated */

#include <jni.h>

 /* header for class com_magc_jni_helloworld */

#ifndef _included_com_magc_jni_helloworld

#define _included_com_magc_jni_helloworld

#ifdef __cplusplus

extern "c" {

#endif

/*

 * class:     com_magc_jni_helloworld

 * method:    displayhello

 * signature: ()v

 */

jniexport void jnicall java_com_magc_jni_helloworld_displayhello

  (jnienv *, jobject);

注:1)、此頭檔案是不需要使用者編譯的,直接供其它c、c++程式引用。

     2)、此頭檔案中的java_com_magc_jni_helloworld_displayhello(jnienv *, jobject)方法,是将來與動态連結庫互動的接口,并需要名字保持一緻。

  jni_helloworldimpl.cpp:

#include "com_magc_jni_helloworld.h"

    #include <stdio.h>

(jnienv *env, jobject obj)

{

    printf("from jni_helloworldimpl.cpp :");

    printf("hello world ! \n");

    return;

此c++檔案實作了上述頭檔案中的函數,注意方法函數名要保持一緻。

編譯生成動态庫libhello.so,

JNI 簡介、基本原理
JNI 簡介、基本原理

總結了一下,jni一般有以下一些應用場景

1.高性能 ,在一些情況下因為處理運算量非常大,為了擷取高性能,直接使用java是不能勝任的,如:一些圖形的處理

2.調用一些硬體的驅動或者一些軟體的驅動,比如調用一些外部系統接口的驅動,如:讀卡器的驅動,oci驅動

3.需要使用大記憶體,遠遠超過jvm所能配置設定的記憶體,如:程序内cache

4.調用c或者作業系統提供的服務,如:java調用搜尋服務,其中搜尋是由c/c++實作的,不過這個一般可以設計成更加通用的方式,比如soa的方式

所有這些場景的前提是犧牲了java代碼的可移植性,不同的os,甚至版本都需要寫不同版本的native實作

經測試jni實作方法比普通java方法快13~15倍。

參考:

如有問題請留言,轉載注明出處。