1. 程式人生 > >Java 呼叫C語言JNI庫(Hello World例項)

Java 呼叫C語言JNI庫(Hello World例項)

要在java中呼叫c語言的庫,一直覺得很不可思議,但是Java提供了JNI這個東西,這也就變得可能了. 作為一個碼農,我們還是從最簡單的 Hello World開始吧.

首先說一下我們想要做的事情. 在c語言中定義一個 void sayHello()函式(列印Hello World);然後在Java中呼叫這個函式顯示Hello Word.

現在分別從Java和C語言兩部分說明:

1. Java  部分

  我們首先定義一個HelloNative,在其中申明sayHello函式,函式要申明為Native 型別的.如下:

public class HelloNative {
    public
native void sayHello(); }

編譯這個類,生成class檔案:

javac HelloWorld.java

利用javah生成需要的h檔案

javah HelloNative

生成的 h檔案大概如下:

複製程式碼
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloNative */

#ifndef _Included_HelloNative
#define _Included_HelloNative
#ifdef __cplusplus
extern "C" { #endif /* * Class: HelloNative * Method: sayHello * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloNative_sayHello (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
複製程式碼

我們可以看一下上面自動生成的程式,程式include了jni.h,這個標頭檔案在 $JAVA_HOME下的include資料夾下. 還可以發現生成的函式名是在我們的函式名前面加上了Java_HelloNative.

2. C語言部分

  根據上面生成的h檔案編寫相應的程式碼實現,如我們建立一個 HelloNative.cpp用來實現顯示Hello World的函式.如下:

複製程式碼
#include <stdio.h>
#include "HelloNative.h"

JNIEXPORT void JNICALL Java_HelloNative_sayHello(JNIEnv *, jobject)
{
    printf("Hello World!\n");
}
複製程式碼

程式碼編寫完成之後,我們再用g++(#add,一定不要用gcc,會報錯)編譯成庫檔案,命令如下;

g++ -fPIC -I/usr/lib/jvm/java-7-openjdk-i386/include -I/usr/lib/jvm/java-7-openjdk-i386/include/linux -shared -o libHelloNative.so HelloNative.cpp 

這樣就會在當前目錄下生成一個libHelloNative.so的庫檔案.這時我們需要的庫已經生成,在C語言下的工作已經完成了.

接下來我們需要在Java中編寫一個程式測試一下.在程式前,我們需要將我們的庫載入進去.載入的方法是呼叫Java的 System.loadLibrary("HelloNative"); 

複製程式碼
public class TestNative 
{
    static {
        try { 
            System.loadLibrary("HelloNative"); //沒有lib字首
        } 
        catch(UnsatisfiedLinkError e) { 
            System.out.println( "Cannot load hello library:\n " + e.toString() ); 
        }
    }
    public static void main(String[] args) {
        HelloNative test = new HelloNative();
        test.sayHello();
    }
}
複製程式碼

但是再我們編譯後,執行的時候,問題又出現了.

Cannot load hello library:
 java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path
Exception in thread "main" java.lang.UnsatisfiedLinkError: HelloNative.sayHello()V
    at HelloNative.sayHello(Native Method)
    at TestNative.main(TestNative.java:13)

載入庫失敗,但是我們的庫明明就是放在當前資料夾下的,怎麼會載入失敗呢?

我們用System.getProperty("java.library.path")檢視,發現java.library.path中並不u存在當前的目錄.主要有以下的幾個解決辦法:

1) 將生成的庫複製到java.library.path有的路徑中去,當然這樣不是很好

2) 設定環境變數export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ,將當前的目錄加入到LD_LIBRARY_PATH中

3) 設定java 的選項,將當前的目錄加入到其中 .java -Djava.library.path=. $LD_LIBRARY_PATH

這樣之後我們的程式就能夠成功的運行了.可以看見顯示的"Hello World!"了