JAVA的JNI調用

 

    因爲JNI調用C和調用C++差很少,並且C++中能夠混合寫C代碼,因此這裏主要是寫關於JNI調用C++的部分。html

  •  通常步驟:

  1. 先是寫普通的Java類,其中包括本地方法調用。 
  2. 而後編譯這個Java類,調用javah命令,生成.h頭文件
  3. 接着,就是實現頭文件中的函數;實現過程當中有點比較麻煩,要知道JNI中JAVA和C/C++的類型轉換,好比數組類型的轉換,基本類型的轉換等,最好是看文檔,或者網上找相關資料。

 

    源代碼連接http://files.cnblogs.com/GDUT/jni-demo.rarjava

 

  • JNI的調用效果圖:

 

 

  • 下面是調用JNI的具體過程:

 

      1.  普通Java類(包含測試方法):MyJNI.java數組

 1 public class MyJNI {
 2 
 3     //加載動態連接庫
 4     static {
 5         System.out.println("開始加載動態連接庫");
 6         System.loadLibrary("MyJNI");
 7         System.out.println("動態連接庫加載完畢。");
 8     }
 9     
10     public native void go();
11     
12     public native void run();
13     
14     public native String getName();
15     
16     public native int[] sort(int[] array);
17     
18     //測試
19     public static void main(String[] args) {
20         MyJNI jni = new MyJNI();
21         int[] array = {5, 3, 6, 35, 74, 8}, sortedArray;
22         
23         jni.run();
24         jni.go();
25         jni.getName();
26         sortedArray = jni.sort(array);
27         //因爲這是本地方法調用,這裏的數組和日常的數組的引用不太同樣。
28         
29         for(int i=0; i<sortedArray.length; i++){
30             System.out.print(sortedArray[i] + "\t");
31         }
32             
33     }
34 }

 

        2.  由Java類編譯後生成的C++頭文件:MyJNI.h函數

 1 /* DO NOT EDIT THIS FILE - it is machine generated */
 2 #include <jni.h>
 3 /* Header for class MyJNI */
 4 
 5 #ifndef _Included_MyJNI
 6 #define _Included_MyJNI
 7 #ifdef __cplusplus
 8 extern "C" {
 9 #endif
10 /*
11  * Class:     MyJNI
12  * Method:    go
13  * Signature: ()V
14  */
15 JNIEXPORT void JNICALL Java_MyJNI_go
16   (JNIEnv *, jobject);
17 
18 /*
19  * Class:     MyJNI
20  * Method:    run
21  * Signature: ()V
22  */
23 JNIEXPORT void JNICALL Java_MyJNI_run
24   (JNIEnv *, jobject);
25 
26 /*
27  * Class:     MyJNI
28  * Method:    getName
29  * Signature: ()Ljava/lang/String;
30  */
31 JNIEXPORT jstring JNICALL Java_MyJNI_getName
32   (JNIEnv *, jobject);
33 
34 /*
35  * Class:     MyJNI
36  * Method:    sort
37  * Signature: ([I)[I
38  */
39 JNIEXPORT jintArray JNICALL Java_MyJNI_sort
40   (JNIEnv *, jobject, jintArray);
41 
42 #ifdef __cplusplus
43 }
44 #endif
45 #endif

 

       3.  須要調用的C++函數的相關文件:MyJNIImpl.cpp測試

 1 #include <jni.h>
 2 #include "MyJNI.h"
 3 #include <stdio.h>
 4 
 5 
 6 /*
 7  * Class:     MyJNI
 8  * Method:    go
 9  * Signature: ()V
10  */
11 JNIEXPORT void JNICALL Java_MyJNI_go
12   (JNIEnv * env, jobject jobj){
13 
14     printf("I am going....\n");
15 }
16 
17 /*
18  * Class:     MyJNI
19  * Method:    run
20  * Signature: ()V
21  */
22 JNIEXPORT void JNICALL Java_MyJNI_run
23   (JNIEnv * env, jobject jobj){
24 
25     printf("I am running....\n");
26 }
27 
28 /*
29  * Class:     MyJNI
30  * Method:    getName
31  * Signature: ()Ljava/lang/String;
32  */
33 JNIEXPORT jstring JNICALL Java_MyJNI_getName
34   (JNIEnv * env, jobject job){
35 
36    printf("I am GDUTtiantian, go with me.\n");
37    //將字符串轉化爲jstring類型
38    //jstring就是對應java的String類型
39    jstring p = env->NewStringUTF("GDUTtiantian");
40    return p;
41 }
42 
43 /*
44  * Class:     MyJNI
45  * Method:    sort
46  * Signature: ([I)[I
47  */
48 JNIEXPORT jintArray JNICALL Java_MyJNI_sort
49   (JNIEnv * env, jobject jobj, jintArray array){
50 
51 jint* arr;//定義一個整形指針
52     int sum=0;
53     //對於整形數組的處理,主要有GetIntArrayElements與GetIntArrayRegion
54     //第一種方法
55     arr = env->GetIntArrayElements(array, NULL);//獲得一個指向原始數據類型內容的指針
56     jint length = env->GetArrayLength(array);//獲得數組的長度
57 
58     for(int i=0; i<length; i++){
59         for(int j=i+1; j<length; j++){
60             if(arr[i] > arr[j]){
61                 jint temp = arr[i];
62                 arr[i] = arr[j];
63                 arr[j] = temp;
64             }
65         }
66     }
67 
68 
69     for(int i=0; i<length; i++){
70         printf("%d ", arr[i]);
71     }
72 
73     printf("\n排序完成\n");
74 
75     jintArray javaArray = env->NewIntArray(length);
76     env->SetIntArrayRegion(javaArray, 0, length, arr);
77 
78     return javaArray;//返回排序後的數組
79 }

 

 

編譯以後,生成一個動態連接庫文件:MyJNI.dllspa

在Java類中就是經過加載這個庫文件,調用其中的相關函數。.net

調用的相關命令:3d

  • javac *.java
  • javah MyJNI
  • set JAVA_HOME=D:\SoftwareDeveloping\jdk32bit_1.6
  • g++ -Wl,--add-stdcall-alias -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -shared -o MyJNI.dll MyJNIImpl.cpp
  • java MyJNI

 

  • 在操做過程當中可能會出現的異常:

  1.  第一個異常 
 1 C:\Users\Administrator\Desktop>java HelloJNI
 2 Exception in thread "main" java.lang.UnsupportedClassVersionError: HelloJNI : Unsupported major.minor version 51.0
 3         at java.lang.ClassLoader.defineClass1(Native Method)
 4         at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
 5         at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
 6         at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
 7         at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
 8         at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
 9         at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
10         at java.security.AccessController.doPrivileged(Native Method)
11         at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
12         at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
13         at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
14         at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
15 Could not find the main class: HelloJNI.  Program will exit.

這個是JAVA虛擬機的版本低於編譯器的問題,若是你用一個編譯編譯以後,而後把.class文件移動到另外一個環境下執行,可能會出現這個問題。指針

 

  2.     第二個異常code

 1 C:\Users\Administrator\Desktop>javac *.java
 2 
 3 C:\Users\Administrator\Desktop>java HelloJNI
 4 Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\Users\Administrator\Desktop\hello.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform
 5         at java.lang.ClassLoader$NativeLibrary.load(Native Method)
 6         at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1807)
 7         at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1732)
 8         at java.lang.Runtime.loadLibrary0(Runtime.java:823)
 9         at java.lang.System.loadLibrary(System.java:1028)
10         at HelloJNI.<clinit>(HelloJNI.java:3)
11 Could not find the main class: HelloJNI.  Program will exit.

動態連接庫.dll是32位,而JVM是64位,不匹配;能夠安裝一個32位的JVM;或者在64位環境下從新編譯一個新的.dll文件。

    3.    第三個異常

 1 C:\Users\Administrator\Desktop\jni>g++ -Wl,--add-stdcall-alias -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -shared -o MyJNI.dll MyJNIImpl.cpp
 2 In file included from MyJNIImpl.cpp:1:
 3 MyJNI.h:2:17: jni.h: No such file or directory
 4 In file included from MyJNIImpl.cpp:1:
 5 MyJNI.h:15: error: expected constructor, destructor, or type conversion before "void"
 6 MyJNI.h:15: error: expected `,' or `;' before "void"
 7 MyJNI.h:23: error: expected constructor, destructor, or type conversion before "void"
 8 MyJNI.h:23: error: expected `,' or `;' before "void"
 9 MyJNI.h:31: error: `JNIEXPORT' does not name a type
10 MyJNI.h:39: error: `JNIEXPORT' does not name a type
11 MyJNIImpl.cpp:10: error: expected constructor, destructor, or type conversion before "void"
12 MyJNIImpl.cpp:10: error: expected `,' or `;' before "void"
13 MyJNIImpl.cpp:21: error: expected constructor, destructor, or type conversion before "void"
14 MyJNIImpl.cpp:21: error: expected `,' or `;' before "void"
15 MyJNIImpl.cpp:32: error: `JNIEXPORT' does not name a type
16 MyJNIImpl.cpp:47: error: `JNIEXPORT' does not name a type

這個報錯主要是找不到jni.h文件,通常的緣由:JAVA_HOME的路徑有問題,注意這個路徑是安裝路徑。用命令設置下,若是設置仍是報這個錯誤,那麼就到環境變量那裏修改。

 

參考資料:http://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html

    

JNI類型轉換:http://www.cnblogs.com/lgydqy/archive/2012/02/28/2371592.html

函數

Java 數組類型

本地類型

GetBooleanArrayElements

jbooleanArray

jboolean

GetByteArrayElements

jbyteArray

jbyte

GetCharArrayElements

jcharArray

jchar

GetShortArrayElements

jshortArray

jshort

GetIntArrayElements

jintArray

jint

GetLongArrayElements

jlongArray

jlong

GetFloatArrayElements

jfloatArray

jfloat

GetDoubleArrayElements

jdoubleArray

jdouble

 

 

歡迎討論交流, 個人主頁:http://www.cnblogs.com/GDUT/

                    個人郵箱:zone.technology.exchange@gmail.com

相關文章
相關標籤/搜索