1. 程式人生 > >Linux下JNI呼叫簡單例項操作全過程

Linux下JNI呼叫簡單例項操作全過程

開發環境:Linux(Ubuntu 11.04) + JDK 7
例項說明:利用JNI呼叫原生代碼的方法來實現一個計算Int陣列總和的功能


使用JNI呼叫原生代碼,整個開發流程主要包括以下幾個步驟:
1、建立一個Java類(IntArray.java);
2、使用javac編譯該類(生成IntArray.class);
3、使用javah -jni 產生標頭檔案(生成IntArray.h);
4、使用原生代碼實現標頭檔案中定義的方法(編寫IntArray.c);
5、編譯生成本地動態庫(生成libIntArray.so);
6、使用Java執行程式。


一、建立一個Java類(IntArray.java)
class IntArray{
private native int sumArray(int[] arr);
public static void main(String[]args){
IntArray p = new IntArray();
int arr[] = new int[10];
for(int i =0;i<10;i++){
arr[i] = i;
}

int sum = p.sumArray(arr);
System.out.println("Sum = "+sum);
}

static{
System.loadLibrary("IntArray");
}
}注:
1、在Java程式碼中宣告本地方法必須有"native"識別符號,native修飾的方法,在Java程式碼中只作為宣告存在。例如: private native int sumArray(int[] arr);
2、在呼叫本地方法前,必須首先裝載含有該方法的本地庫. 如IntArray.java中所示,置於static塊中,在Java VM初始化一個類時,首先執行這部分程式碼,這可保證呼叫本地方法前,裝載了本地庫。
static{
System.loadLibrary("IntArray");
}

二、使用javac編譯該類(生成IntArray.class)
javac IntArray.java
三、使用javah -jni 產生標頭檔案(生成IntArray.h)
javah -jni IntArray
生成IntArray.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class IntArray */

#ifndef _Included_IntArray
#define _Included_IntArray
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: IntArray
* Method: sumArray
* Signature: ([I)I
*/
JNIEXPORT jint JNICALL Java_IntArray_sumArray
(JNIEnv *, jobject, jintArray);

#ifdef __cplusplus
}
#endif
#endif

四、使用原生代碼實現標頭檔案中定義的方法(編寫IntArray.c)
複製IntArray.h成IntArray.c,對於IntArray.c做以下修改:
1、新增標頭檔案:#include "IntArray.h"
2、去掉以下幾句
#ifndef _Included_IntArray
#define _Included_IntArray
#endif
3、實現標頭檔案中定義的方法

IntArray.c具體程式碼如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class IntArray */
#include "IntArray.h"

#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: IntArray
* Method: sumArray
* Signature: ([I)I
*/
JNIEXPORT jint JNICALL Java_IntArray_sumArray
(JNIEnv *env, jobject obj, jintArray arr)
{
jint buf[10] ={0};
jint i = 0,sum = 0;

(*env)->GetIntArrayRegion(env,arr,0,10,buf);

for(i=0;i<10;i++)
{
sum += buf[i];
}

return sum;
}
#ifdef __cplusplus
}
#endif

五、編譯生成本地動態庫(生成libIntArray.so)
根據原生代碼(IntArray.h,IntArray.c)生成本地動態庫,命令如下:
gcc -I/usr/lib/jvm/java-7-sun/include/ -I/usr/lib/jvm/java-7-sun/include/linux/ -fPIC -shared -o libIntArray.so IntArray.c注:
其中 -I後面是java的include資料夾地址,請根據您具體的java版本以及安裝路徑作相應改變;
-f後面的PIC表示生成的庫中符號是與位置無關的(PIC就是Position Independent Code),關於PIC,可以參考這篇文章
<a href="<a href="http://www.gentoo.org/proj/en/hardened/pic-guide.xml" >introduction"="" style="box-sizing: border-box; color: rgb(51, 51, 51); text-decoration: none; outline: none medium; transition: all 0.25s; -webkit-transition: all 0.25s;">http://www.gentoo.org/proj/en/hardened/pic-guide.xml">Introduction to Position Independent Code</a> 
-shared表示共享,共享庫字尾名.so可以認為是shared object的簡稱;
-o libIntArray.so,可以理解為編譯後輸出libIntArray.so庫。

更詳細地說:

-shared 該選項指定生成動態連線庫(讓聯結器生成T型別的匯出符號表,有時候也生成弱連線W型別的匯出符號),不用該標誌外部程式無法連線。相當於一個可執行檔案
-fPIC:表示編譯為位置獨立的程式碼,不用此選項的話編譯後的程式碼是位置相關的所以動態載入時是通過程式碼拷貝的方式來滿足不同程序的需要,而不能達到真正程式碼段共享的目的。
-L.:表示要連線的庫在當前目錄中
-ltest:編譯器查詢動態連線庫時有隱含的命名規則,即在給出的名字前面加上lib,後面加上.so來確定庫的名稱
LD_LIBRARY_PATH:這個環境變數指示動態聯結器可以裝載動態庫的路徑

六、使用Java執行程式
java IntArray

可能出現以下結果:
[email protected]:~$ java IntArray
Exception in thread "main" java.lang.UnsatisfiedLinkError: no IntArray in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
at java.lang.Runtime.loadLibrary0(Runtime.java:845)
at java.lang.System.loadLibrary(System.java:1084)
at IntArray.<clinit>(IntArray.java:15)
分析異常提示可知,我們之前生成的共享庫不在系統預設的共享庫路徑中,程式找不到共享庫報錯。
解決方法有兩個:
1、臨時指定共享庫libIntArray.so的路徑。
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH注:該方法只在當前會話視窗有效,切換到另外一個終端視窗,則需要重新指定共享庫路徑。

2、執行時加上引數指定共享庫libIntArray.so的路徑。
java -Djava.library.path=. IntArray注:-D:設定Java平臺的系統屬性。 此時JavaVM可以在當前位置找到該庫。

通過以上任意方法,您都可以得到正確的執行結果:
[email protected]:~$ java IntArray
Sum = 45

轉載自:http://m.2cto.com/os/201108/101048.html

另外,該過程需要linux系統下安裝有jdk和gcc/g++,推薦使用g++編譯,因為gcc編譯容易出錯。

操作過程中注意.cpp檔案內的extern C需要用__cplusplu包住,否則會提示jni.h和jni_m.h的錯誤和警告。

操作過程中.h檔案一定要與java檔案自動生成名稱一致,否則會出現呼叫函式失敗的錯誤,也就是執行報錯但編譯不會報錯。

相關推薦

LinuxJNI呼叫簡單例項操作全過程

開發環境:Linux(Ubuntu 11.04) + JDK 7 例項說明:利用JNI呼叫原生代碼的方法來實現一個計算Int陣列總和的功能 使用JNI呼叫原生代碼,整個開發流程主要包括以下幾個步驟: 1、建立一個Java類(IntArray.java); 2、使用ja

Linux系統呼叫實現檔案操作

系統呼叫(系統呼叫是作業系統提供給使用者程式的一組“特殊”函式介面,使用者通過這組介面獲得作業系統提供的服務)中操作I/O的函式,都是針對檔案描述符的。 通過檔案描述符可以直接對相應檔案進行操作,如:open、close、write、read、ioctl #define STDIN_FIL

LinuxC++呼叫Java簡單例項jni

假設工作目錄為/home1. Java端1)  mkdir leixf && cd leixf2) 建立SubClass.java檔案,內容如下:package leixf;public class SubClass {private String name

LinuxMySQL的簡單操作

max name 失效 發現 root用戶 修改 statement times l數據庫 更改mysql數據庫root的密碼 首次進入數據庫是不用密碼的: [root@localhost ~]# /usr/local/mysql/bin/mysql -uroot W

Android呼叫JNI簡單例項(附詳細步驟)

最近想呼叫FFmepg庫來做編解碼的東西,首先就得學會使用JNI(JAVA Native Interface)呼叫。 下面做個簡單的JNI呼叫例項,中間遇到的問題及解決過程省略一萬字,查詢到的資料也都

LinuxJava呼叫MySql的第一個例子(全過程) 及 MySql改密碼的種種誤區

第三步:解壓mysql-connector-java-5.1.24.tar.gz這個檔案到/usr/local/java/。事實上這個目錄是任意的,只不過為了方便。我把jdk和eclipse都安裝到了上面這個目錄下。如下所示:第四步:新建一個TestMySql工程,右鍵工程-

LinuxC程式設計-----IO/檔案操作/記憶體對映 實現簡單記錄儲存(3)

利用linux下的檔案記憶體對映可以實現程序共享資料,我們可以把一個檔案對映到虛擬記憶體中使多個程序進行共享, 到這裡我們大概能想到他能應用到的領域 是很廣泛的  主要涉及到 mmap  munmap   msync 三個函式的應用 下面貼程式碼  下面一段程式碼是為檔案

linux 的文件目錄操作之遍歷目錄

ges div strcmp pen fprintf pwd edi while font   通過遞歸調用讀取目錄和文件信息去遍歷整個目錄:   示例代碼: 1 #include <unistd.h> 2 #include <stdio.h>

002-Linux防火墻相關命令操作

style 默認 ice 查看 開機啟動 操作 run ted spa   linux的各個版本或同一個版本間不同版本號關於防火墻命令也會有不一樣的。針對這些命令整理如下,方便自己或有需要的朋友查閱。 centOS 6.5關閉防火墻步驟 關閉命令: se

linuxsendmail郵件系統安裝操作記錄

src 文件中 mage 本機 acc 現在 echo log lin 電子郵件系統的組成:1)郵件用戶代理(Mail User Agent , MUA),MUA是一個郵件系統的客戶端程序,它提供了閱讀,發送和接受電子郵件的用戶接口。 最常用的 MUA 有: linux 中

linuxspi-nor Flash的操作----備份與還原norflash中的uboot

一、環境: Ubuntu 16.02 nor flash型號: spi nor flash S25FL256S ,Sector Size = 64 kbytes,  total size = 256M BIT = 32M Bytes 一、備份: dd if=/dev/mtd

Linux一個最簡單的不依賴第三庫的的C程式(1)

如下程式碼是一段彙編程式碼,雖然標題中使用了C語言這個詞語,但下面確實是一段彙編程式碼,弄清楚了這個程式碼,後續的知識點才會展開。 #PURPOSE: Simple program that exits and returns a # status code back to the Lin

linux的selinux簡單運用

首先通過getenforce命令我們可以檢視selimux狀態 通過vim /etc/sysconfig/selinux 編輯selimux配置檔案,啟動 引數SELINUX=enforcing  強制狀態,不可以操作,也會發出警告    &

linuxJNI開發—HelloWord為例

轉自:https://www.cnblogs.com/snake-hand/archive/2012/05/25/2517412.html 前期準備: 1、Java JDK 2、gcc 3、g++ 確保上述準備工作完成後開始下邊的工作: Java程式碼: public class H

HTML拉選擇 簡單例項 新增刪除節點到另一個節點

 下拉選擇 簡單例項   <html> <head> <title>HTML</title> <style type="text/css"> </style> </h

LinuxJNA 呼叫 so 庫

原文:https://blog.csdn.net/withiter/article/details/8077470  博文連結:https://i.cnblogs.com/EditPosts.aspx?opt=1在linux下使用jna呼叫本地方法的時候,需要將C寫成的程式編譯為so檔案1、寫一個簡

Linux c語言連線與操作MYSQL

1.安裝mysql 2.安裝mysql.h函式庫 sudo apt-get install libmysqlclient-dev 3. mysql_real_connect() 連線一個mysql伺服器  語法如下 MYSQL *mysql_real_connect

前言:JNI呼叫-簡單使用

JNI JNI是(Java Native Interface  本地介面)是一個協議,用來溝通Java 程式碼和C/C++程式碼,是 Java和 C、C++之間的橋樑。 通過JNI協議,Java可以呼叫外部C、C++定義好的函式庫,外部C、C++也可以呼叫Java封裝好的類和方法

Linux配置LAMP架構例項(建立論壇)

LAMP (Web應用軟體組合) Linux+Apache+Mysql/MariaDB+Perl/PHP/Python一組常用來搭建動態網站或者伺服器的開源軟體,本身都是各自獨立的程式,但是因為常被放在一起使用,擁有了越來越高的相容度,共同組成了一個強大的Web應用程式平臺。隨著開源潮流

Linux實現 OpenSSL 簡單加密與解密字串

場景 shell指令碼中存在明文密碼 客戶要求禁止使用明文密碼,密碼做加密處理. 方案 在網上了解到了Linux OpenSSL加密解密工具 可以指定各種加密演算法為字元,檔案做加密處理. 加密的案例比較多,解密的寥寥無幾. 有興趣的可以去查下中文教程 案例中使用加密演算法 : AES 例項