JAVA的JNI调用

 

    由于JNI调用C和调用C++差不多,而且C++中可以混合写C代码,所以这里主要是写关于JNI调用C++的部分。

  •  一般步骤:

  1. 先是写普通的Java类,其中包括本地方法调用。 
  2. 然后编译这个Java类,调用javah命令,生成.h头文件
  3. 接着,就是实现头文件中的函数;实现过程中有点比较麻烦,要知道JNI中JAVA和C/C++的类型转换,比如数组类型的转换,基本类型的转换等,最好是看文档,或者网上找相关资料。

 

    源代码链接http://files.cnblogs.com/GDUT/jni-demo.rar

 

  • 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.dll

在Java类中就是通过加载这个库文件,调用其中的相关函数。

调用的相关命令:

  • 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.     第二个异常

 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

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/GDUT/p/3806771.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值