1. 程式人生 > >Java 呼叫本地Native介面指引

Java 呼叫本地Native介面指引

Java本地介面允許java使用者用程式碼與其他語言介面互動的一種方法,native方法允許java語言呼叫其他語言,增加了程式碼的靈活性

1、Java本地介面的好處

通過使用Java介面,可以增加程式碼的靈活性與重用性,假如我們想在java裡用一段C語言的程式碼實現的功能,我們不用全部重寫所有C語言程式碼,而是可以加一個C語言介面類,與java互動即可。 通過java介面,還可以提升java程式的效能瓶頸,我們知道,java在執行的時候由於需要執行在jvm上,因此效率會有所下降,這也是為了跨平臺性做了一個折中的辦法,通過jni,我們可以將一些程式碼放在native程式碼中,通常native程式碼的速度比java程式碼快很多,因此可以提升java程式的效能。

2、Java本地方法的開發過程

目的:實現一個Hello類,在Hello類裡面定義一個native'的方法,並且這個方法轉由C語言實現。 首先,我們建立一個Hello類:
public class Hello {
	public native void sayHi(); //1
    static { System.loadLibrary("hello"); } //2

	public static void main (String[] args) {
	    Hello hello = new Hello();
		System.out.println("I will Print:");
		hello.sayHi();//3
	}
}

其中,第一步建立一個native的sayHi方法,方法的實現並未實現,而是由下面的C語言來實現。 第二步載入C語言庫,在windows下,庫名為hello.dll,在Linux下,庫名為libhello.so,在macos系統下庫名為libhello.jnilib 第三步在main方法裡面呼叫我們定義的native方法,來驗證我們的方法是否成功執行。 其次,通過javac工具編譯這個類:
$ javac Hello.java 

如果是有包的話需要加上包路徑名。 然後,用javah工具建立native的.h標頭檔案,這個檔案為自動生成
$ javah -jni Hello

建立好之後,我們的資料夾中就多了個Hello.h標頭檔案:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Hello */

#ifndef _Included_Hello
#define _Included_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Hello
 * Method:    sayHi
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_Hello_sayHi
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

這個檔案裡定義了我們需要實現的函式原型:
JNIEXPORT void JNICALL Java_Hello_sayHi
  (JNIEnv *, jobject);
然後我們需要實現具體的定義,建立一個hello.c檔案:
#include<stdio.h>
#include"Hello.h"

JNIEXPORT void JNICALL
Java_Hello_sayHi(JNIEnv *env, jobject obj) {
    printf("Hello World\n");
}

在實現中,我們需要include我們剛才自動建立好的.h檔案,並且實現它定義的函式。 然後我們生成.so庫檔案:
$ gcc -o libhello.so -fPIC -lc -shared -I /usr/lib/jvm/java/include -I /usr/lib/jvm/java/include/linux hello.c
-o為輸出檔名,不能隨意更改,要以lib+庫名(就是java程式碼裡loadLibrary裡的字串)+.so命名 -I 由於需要jni.h和其他的一些標頭檔案,需要加上依賴的標頭檔案路徑 然後我們需要把當前檔案目錄加入庫檔案路徑中:
$ export LD_LIBRARY_PATH=.
ok,至此已經全部完成操作,最後我們java Hello就可以執行程式碼了。

3、可能出錯的地方

常見的錯誤有兩個地方,一個是: java.lang.UnsatisfiedLinkError: no HelloWorld in java.library.path,這個是由於找不到庫檔案所致的,原因有很多,最常見的是檔名規則設定錯誤,或者沒有export  LD_LIBRARY_PATH使得java找不到庫檔案。 還有一個錯誤的是:Exception in thread "main" java.lang.UnsatisfiedLinkError: xxx.xxx.HelloWorld.myprint()V,這個是由於我們的庫雖然找到了,但是定義卻是錯誤的,大多數原因是我們自己寫的函式名有錯誤,或者引數有錯誤所致,仔細檢查一遍即可。