java訪問C/C++有6步
1.寫java檔案
2.編譯java產生class
3.產生C/C++標頭檔。
4.寫C/C++檔案
5.編譯產生dll(Window下)或so檔案
6.運行java程式
下面介紹ubutun下一個JNI例子
1.編寫Sample1.java檔案:
public class Sample1<br /> {<br />public native int intMethod(int n);<br />public native boolean booleanMethod(boolean bool);<br />public native String stringMethod(String text);<br />public native int intArrayMethod(int[] intArray);</p><p>public static void main(String[] args)<br />{<br />System.loadLibrary("Sample1");<br />Sample1 sample = new Sample1();<br />int square = sample.intMethod(5);<br />boolean bool = sample.booleanMethod(true);<br />String text = sample.stringMethod("JAVA");<br />int sum = sample.intArrayMethod(<br />new int[]{1,1,2,3,5,8,13} );</p><p>System.out.println("intMethod: " + square);<br />System.out.println("booleanMethod: " + bool);<br />System.out.println("stringMethod: " + text);<br />System.out.println("intArrayMethod: " + sum);<br /> }<br /> }
兩個地方要注意,
一。上面的方法都用到了native關鍵字。
二。System.loadLibrary("Sample1");這句中"Sample1"是我們在第5步中得到的庫的名字,在window下是"Sample1.dll",在unix下要加首碼"lib",即"libSample1.so"。
2.編譯java檔案:
javac Sample1.java
無錯產生Sample1.class檔案
3.產生C/C++標頭檔
javah Sample1
產生Sample1.h
使用命令 cat Sample1.h 查看,內容為:
/* DO NOT EDIT THIS FILE - it is machine generated */<br />#include <jni.h><br />/* Header for class Sample1 */</p><p>#ifndef _Included_Sample1<br />#define _Included_Sample1<br />#ifdef __cplusplus<br />extern "C" {<br />#endif</p><p>JNIEXPORT jint JNICALL Java_Sample1_intMethod<br />(JNIEnv *, jobject, jint);</p><p>JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod<br />(JNIEnv *, jobject, jboolean);</p><p>JNIEXPORT jstring JNICALL Java_Sample1_stringMethod<br />(JNIEnv *, jobject, jstring);</p><p>JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod<br />(JNIEnv *, jobject, jintArray);</p><p>#ifdef __cplusplus<br />}<br />#endif<br />#endif
我們可以對比看看java檔案中對應的方法
4.編寫C/C++代碼
Sample1.c:
#include "Sample1.h"<br /> #include <string.h><br /> JNIEXPORT jint JNICALL Java_Sample1_intMethod<br /> (JNIEnv *env, jobject obj, jint num) {<br /> return num * num;<br /> }<br /> JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod<br /> (JNIEnv *env, jobject obj, jboolean boolean) {<br /> return !boolean;<br /> }<br /> JNIEXPORT jstring JNICALL Java_Sample1_stringMethod<br /> (JNIEnv *env, jobject obj, jstring string) {<br /> const char *str = (*env)->GetStringUTFChars(env, strin<br /> char cap[128];<br /> strcpy(cap, str);<br /> (*env)->ReleaseStringUTFChars(env, string, str);<br /> return (*env)->NewStringUTF(env, strupr(cap));<br /> }<br /> JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod<br /> (JNIEnv *env, jobject obj, jintArray array) {<br /> int i, sum = 0;<br /> jsize len = (*env)->GetArrayLength(env, array);<br /> jint *body = (*env)->GetIntArrayElements(env, array, 0<br /> for (i=0; i<len; i++)<br /> { sum += body[i];<br /> }<br /> (*env)->ReleaseIntArrayElements(env, array, body, 0);<br /> return sum;<br /> }<br /> void main(){}
Sample1.cpp:#include "Sample1.h"<br />#include <string.h><br />NIEXPORT jint JNICALL Java_Sample1_intMethod<br /> (JNIEnv *env, jobject obj, jint num) {<br /> return num * num;<br />}<br />JNIEXPORT jboolean JNICALL Java_Sample1_booleanMethod<br /> (JNIEnv *env, jobject obj, jboolean boolean) {<br /> return !boolean;<br />}<br />JNIEXPORT jstring JNICALL Java_Sample1_stringMethod<br /> (JNIEnv *env, jobject obj, jstring string) {<br /> const char *str = env->GetStringUTFChars(string, 0);<br /> char cap[128];<br /> strcpy(cap, str);<br /> env->ReleaseStringUTFChars(string, str);<br /> return env->NewStringUTF(strupr(cap));<br />}<br />JNIEXPORT jint JNICALL Java_Sample1_intArrayMethod<br /> (JNIEnv *env, jobject obj, jintArray array) {<br /> int i, sum = 0;<br /> jsize len = env->GetArrayLength(array);<br /> jint *body = env->GetIntArrayElements(array, 0);<br /> for (i=0; i<len; i++)<br /> { sum += body[i];<br /> }<br /> env->ReleaseIntArrayElements(array, body, 0);<br /> return sum;<br /> }<br /> void main(){}
兩個差別就是JNIEnv這個類
C中使用 jsize len = (*env)->GetArrayLength(env,array);
C++中使用 jsize len = env->GetArrayLength(env,array);
5.產生共用庫檔案
編譯Sample1.c檔案
gcc -fPIC -D_REENTRANT -I/usr/lib/java/include -I/usr/lib/java/include/linux -c Sample1.c
編譯用到了jdk include中jni.h,include/linux中jni_md.h兩個標頭檔
/usr/lib/java/include 是jin.h路徑
/usr/lib/java/include、linux 是jni_md.h路徑
此時產生Sampel.o檔案
運行:
gcc -shared Sample1.o -o libSample1.so
產生libSample1.so
6.運行java程式
libSample1.so檔案拷貝到java的載入庫LD_LIBRARY_PATH指向的路徑中:
如果沒有足夠許可權,可以這樣:
(1).在/home下建立一個用來存放.so庫檔案的目錄,比如/home/xxx/lib
(2).把libSample1.so檔案拷貝到該目錄下
(3).運行:export LD_LIBRARY_PATH=/home/xxx/lib (只在當前shall下有效...)
現在運行java Sample1
一切正常後,可以看到運行結果輸出:
intMethod: 25
booleanMethod: false
stringMethod: JAVA
intArrayMethod: 33
完成第一個JNI程式。