如何在linux下創(chuàng)建一個(gè)簡(jiǎn)單的JNI程序HelloWorld
Posted on 2010-12-07 08:39 楊書童 閱讀(1568) 評(píng)論(2) 編輯 收藏 引用 所屬分類: 基礎(chǔ)知識(shí)-基礎(chǔ)語言JNI全名是Java Native Interface,通過JNI技術(shù)可以實(shí)現(xiàn)Java和其他編程語言的互相調(diào)用。這里我們使用的是Java和C的互相調(diào)用,Java提供本地接口,C實(shí)現(xiàn)該本地接口。
我使用的是RHEL 5,主要是為了測(cè)試一下在Linux平臺(tái)下,了解JNI技術(shù)是如何實(shí)現(xiàn)的。通過一個(gè)HelloWorld實(shí)例,具體過程在下面講解。
首先,實(shí)現(xiàn)的是Java本地接口Hello.java,代碼如下所示:

class HelloWorld
{

public native void sayHello();


static
{
System.loadLibrary("HelloWorld");
}


public static void main(String[] args)
{
(new HelloWorld()).sayHello();
}
}
其中,方法聲明為native,其實(shí)HelloWorld類就相當(dāng)于一個(gè)接口,是為其他編程語言聲明的接口。System.loadLibrary("HelloWorld");語句是一個(gè)static塊,也就是在該HelloWorld類加載的時(shí)候進(jìn)行執(zhí)行。其中,該語句實(shí)現(xiàn)了加載本地的動(dòng)態(tài)連接庫(DLL),在Linux平臺(tái)下,動(dòng)態(tài)連接庫文件是以.so作為擴(kuò)展名的,也就是標(biāo)準(zhǔn)對(duì)象(Standard Object)。
對(duì)該本地接口類進(jìn)行編譯:
[root@localhost jni]# javac HelloWorld.java
接著,通過編譯的HelloWorld.class文件,生成C語言的頭文件,執(zhí)行命令:
[root@localhost jni]# javah -jni HelloWorld
可以看到,在當(dāng)前目錄下生成一個(gè)HelloWorld.h文件,該文件就是C的接口文件,為使用C實(shí)現(xiàn)Java接口中定義的方法,可以發(fā)現(xiàn)在HelloWorld.h中有一個(gè)方法聲明:


/**//* DO NOT EDIT THIS FILE - it is machine generated */

#ifndef __HelloWorld__
#define __HelloWorld__

#include <jni.h>

#ifdef __cplusplus
extern "C"


{
#endif

JNIEXPORT void JNICALL Java_HelloWorld_sayHello (JNIEnv *env, jobject);

#ifdef __cplusplus
}
#endif

#endif /* __HelloWorld__ */
然后,用C實(shí)現(xiàn)該方法,在HelloWorld.c文件中,代碼如下:
#include <jni.h>
#include "HelloWorld.h"
#include <stdio.h>


JNIEXPORT void JNICALL Java_HelloWorld_sayHello (JNIEnv *env, jobject obj)
{
printf("Hello,the World!!!");
}
這里,方法簽名為Java_HelloWorld_sayHello (JNIEnv *env, jobject obj),添加了形參obj,否則無法通過編譯。
接下來,生成動(dòng)態(tài)連接庫libHelloWorld.so,執(zhí)行命令:
[root@localhost jni]# gcc -fPIC -shared -o libHelloWorld.so HelloWorld.c
可以在當(dāng)前目錄下看到libHelloWorld.so,動(dòng)態(tài)連接庫文件名稱以lib開頭。將該文件拷貝到usr/lib目錄下面,就可以測(cè)試了。
現(xiàn)在執(zhí)行如下命令進(jìn)行測(cè)試:
[root@localhost jni]# java HelloWorld
輸出如下:
Hello,the World!!!
這只是一個(gè)非常簡(jiǎn)單的例子,主要是了解JNI在Linux下該如何用。在實(shí)際應(yīng)用中,可能會(huì)非常復(fù)雜,并且要記住,一旦使用了JNI技術(shù),系統(tǒng)的可移植性被破壞了。有些應(yīng)用中,正是基于這種特性實(shí)現(xiàn),比如限制軟件的傳播使用,保護(hù)開發(fā)商權(quán)益,等等。
我使用的是RHEL 5,主要是為了測(cè)試一下在Linux平臺(tái)下,了解JNI技術(shù)是如何實(shí)現(xiàn)的。通過一個(gè)HelloWorld實(shí)例,具體過程在下面講解。
首先,實(shí)現(xiàn)的是Java本地接口Hello.java,代碼如下所示:



















其中,方法聲明為native,其實(shí)HelloWorld類就相當(dāng)于一個(gè)接口,是為其他編程語言聲明的接口。System.loadLibrary("HelloWorld");語句是一個(gè)static塊,也就是在該HelloWorld類加載的時(shí)候進(jìn)行執(zhí)行。其中,該語句實(shí)現(xiàn)了加載本地的動(dòng)態(tài)連接庫(DLL),在Linux平臺(tái)下,動(dòng)態(tài)連接庫文件是以.so作為擴(kuò)展名的,也就是標(biāo)準(zhǔn)對(duì)象(Standard Object)。
對(duì)該本地接口類進(jìn)行編譯:
[root@localhost jni]# javac HelloWorld.java
接著,通過編譯的HelloWorld.class文件,生成C語言的頭文件,執(zhí)行命令:
[root@localhost jni]# javah -jni HelloWorld
可以看到,在當(dāng)前目錄下生成一個(gè)HelloWorld.h文件,該文件就是C的接口文件,為使用C實(shí)現(xiàn)Java接口中定義的方法,可以發(fā)現(xiàn)在HelloWorld.h中有一個(gè)方法聲明:
























然后,用C實(shí)現(xiàn)該方法,在HelloWorld.c文件中,代碼如下:










這里,方法簽名為Java_HelloWorld_sayHello (JNIEnv *env, jobject obj),添加了形參obj,否則無法通過編譯。
接下來,生成動(dòng)態(tài)連接庫libHelloWorld.so,執(zhí)行命令:
[root@localhost jni]# gcc -fPIC -shared -o libHelloWorld.so HelloWorld.c
可以在當(dāng)前目錄下看到libHelloWorld.so,動(dòng)態(tài)連接庫文件名稱以lib開頭。將該文件拷貝到usr/lib目錄下面,就可以測(cè)試了。
現(xiàn)在執(zhí)行如下命令進(jìn)行測(cè)試:
[root@localhost jni]# java HelloWorld
輸出如下:
Hello,the World!!!
這只是一個(gè)非常簡(jiǎn)單的例子,主要是了解JNI在Linux下該如何用。在實(shí)際應(yīng)用中,可能會(huì)非常復(fù)雜,并且要記住,一旦使用了JNI技術(shù),系統(tǒng)的可移植性被破壞了。有些應(yīng)用中,正是基于這種特性實(shí)現(xiàn),比如限制軟件的傳播使用,保護(hù)開發(fā)商權(quán)益,等等。