筆者最近有需求:
在linux環境下,需要用c封裝一段算法(考慮到保密性比較高),然後主程序邏輯用java開發,然後用java取調用c語言開發的算法。
其實這樣的例子網上也有很多。
本文參考了這篇博客:http://www.2cto.com/kf/201602/490934.html
目標
用java語言,調用c語言封裝的函數,打印hello world
環境
ubuntu,openjdk8,sublime text(編輯c和java),gcc
大致的步驟
1.用java語言,編寫一個api(接口函數),通過javah自動生成 .h頭文件
2.編寫.c,gcc生成.so文件
3.再寫java類,測試調用封裝的接口
開始
1.用java語言,編寫一個api(接口函數),通過javah自動生成 .h頭文件
1.1編寫JniHelloWorldApi.java
package com;
public class HelloApi{
native void helloworld();
}
helloworld就是交互的函數名
需要注意的是包名是com,如果寫了包名,但實際的物理關係與包名不一樣,後面會碰到一些問題(寫過java的應該都明白我是啥意思)
我的目錄結構是這樣
1.2編譯.java
cd 到helloworld目錄下
java com/HelloApi.java
編譯成功之後,在com目錄下,能看到一個HelloApi.class
1.3動態的生成.h頭文件
javah -jni com.HelloApi
-jni
Causes the javah command to create an output file containing
JNI-style native method function prototypes. This is the default
output; use of -jni is optional.
成功之後,可以看到,有com_HelloApi.h生成
.h文件的內容就不展示了
2.編寫.c,gcc生成.so文件
2.1引入.h頭文件,編寫.c
com_HelloApi.c
#include <stdio.h>
#include <jni.h>
#include "com_HelloApi.h"
JNIEXPORT void JNICALL Java_com_HelloApi_helloworld
(JNIEnv * env, jobject obj){
printf("hello world\n");
}
特別注意兩個地方:
#include <jni.h>和#include "com_HelloApi.h"
函數參數 JNIEnv * env, jobject obj env和obj是筆者加上去的
2.2編譯成.o
命令爲:gcc -fPIC -D_REENTRANT -I /usr/lib/jvm/java-8-openjdk-i386/include -I /usr/lib/jvm/java-8-openjdk-i386/include/linux -c com_HelloApi.c
其中 /usr/lib/jvm/java-8-openjdk-i386是jdk的位置,如果不清楚,可以使用whereis java命令進行確認
2.3編譯成.so
gcc -shared com_HelloApi.o -o com_HelloApi.so
成功之後可以看到 com_HelloApi.so生成
3.再寫java類,測試調用封裝的接口
爲了圖方便,筆者,繼續在HelloApi中修改,代碼爲:
package com;
public class HelloApi{
native void helloworld();
static{
System.load("/home/robin/文檔/jni-test/helloworld/com_HelloApi.so");
}
public static void main(String[] args) {
HelloApi ha=new HelloApi();
ha.helloworld();
}
}
System.load()中,參數爲.so文件的絕對路徑
main是我的測試函數
然後再此javac
最後通過 java com.HelloApi可以看到輸出