Java JNI简单实现
         JNI(Java Native Interface)允许了Java和C&C++进行交互?这不折腾人嘛!
 
一、JNI简述
         http://baike.baidu.com/view/1272329.htm,真心懒了-_-!
 
二、JNI基本类型
         copy表一份,很详细的了!
Java 类型
本地类型
描述
boolean
jboolean
C/C++8位整型
byte
jbyte
C/C++带符号的8位整型
char
jchar
C/C++无符号的16位整型
short
jshort
C/C++带符号的16位整型
int
jint
C/C++带符号的32位整型
long
jlong
C/C++带符号的64位整型
float
jfloat
C/C++32位浮点型
double
jdouble
C/C++64位浮点型
Object
jobject
任何Java对象,或者没有对应java类型的对象
Class
jclass
Class对象
String
jstring
字符串对象
Object[]
jobjectArray
任何对象的数组
boolean[]
jbooleanArray
布尔型数组
byte[]
jbyteArray
比特型数组
char[]
jcharArray
字符型数组
short[]
jshortArray
短整型数组
int[]
jintArray
整型数组
long[]
jlongArray
长整型数组
float[]
jfloatArray
浮点型数组
double[]
jdoubleArray
双浮点型数组
表2 Java类型映射
 
三、Java调用C&C++
         1)Java类中编写native声明的方法。
         2)javah命令生成JNI样式.h文件。
         貌似我一直是直接建一个.h,然后copy之前的改改完事。需要注意以下几点:1、JNI调用函数必须要用C编译器编译。也就是C++别忘了extern "C"那块;2、方法名格式:Java_pacakege_class_method。
 
例子程序的HelloJni.h文件:
 
   
   
   
   
  1. #ifndef HELLOJNI_H_ 
  2. #define HELLOJNI_H_ 
  3.  
  4. #include  
  5.  
  6. // JNI调用函数必须要用C编译器编译 
  7. // C++不加extern "C",调用会有异常 
  8. #ifdef __cplusplus 
  9. extern "C" { 
  10. #endif 
  11.  
  12. /* 
  13.  * 1、JNIEXPORT、JNICALL:jni的宏 
  14.  * 2、jstring:返回值类型(对应java的string) 
  15.  * 3、C方法名:Java_pacakege_class_method 
  16.  * 4、JNIEnv*、jobject:jni必要参数(jni环境、java对象) 
  17.  */ 
  18. JNIEXPORT void JNICALL Java_org_join_jni_JniTest_sayHelloWin (JNIEnv*, jobject, intintintint); 
  19.  
  20. #ifdef __cplusplus 
  21. #endif 
  22.  
  23. #endif /* HELLOJNI_H_ */ 
 
         3)用C&C++方法实现本地方法,编译成动态库
         4)Java类中用System.loadLibrary()或System.load()方法加载生成的dll文件
                  System.loadLibrary():装载Windows\System32下或 jre\bin或 Tomcat\bin目录下的本地链接库
                  System.load():根据具体的目录来加截本地链接库,必须是绝对路径
         5)OK!
 
         注意jni方法的使用,C&C++格式是不一样的,如下:
                  C 格式:(*env) -> (env, )

                  返回jstring:return (*env)->NewStringUTF(env, "XXX");

                  C++ 格式:env -> ()
                  返回jstring:return env->NewStringUTF("XXX");
 
         另外数组类型的话,jni提供了操作的函数,稍复杂点,例子里没写也就不说了。
 
四、C&C++回调Java
         直接看代码吧,每步都有注释了。
 
1)包org.join.jni下类JniTest内定义的两方法
   
   
   
   
  1. /** C回调Java方法(静态) */ 
  2. public static int add(int x, int y) { 
  3. System.out.println("==Java静态add方法=="); 
  4. return x + y; 
  5.  
  6. /** C回调Java方法(非静态) */ 
  7. public int sub(int x, int y) { 
  8. System.out.println("==Java非静态sub方法=="); 
  9. return x - y; 
 
2)CallJava.h
   
   
   
   
  1. #ifndef CALLJAVA_H_ 
  2. #define CALLJAVA_H_ 
  3.  
  4. #include  
  5. #include  
  6. #include  
  7.  
  8. int add(JNIEnv*, intint); 
  9. int sub(JNIEnv*, intint); 
  10.  
  11. jobject getInstance(JNIEnv*, jclass); 
  12.  
  13. #endif /* CALLJAVA_H_ */ 
 
3)CallJava.cpp
   
   
   
   
  1. #include "CallJava.h" 
  2.  
  3. /** 
  4.  * C回调Java方法(静态) 
  5.  */ 
  6. int add(JNIEnv *env, int x, int y) { 
  7.     // 获取类 
  8.     jclass AnalyzeCidUtil = env->FindClass("org/join/jni/JniTest"); 
  9.     if (NULL == AnalyzeCidUtil) { 
  10.         return -1; 
  11.     } 
  12.  
  13.     // 获取类add静态方法 
  14.     /* 
  15.      * 第三个参数为方法签名 
  16.      * 
  17.      * 可用JDK自带工具javap生成该类所有方法签名 
  18.      * 控制台进入该类class文件目录,输入:javap -s -private 类名 
  19.      */ 
  20.     jmethodID add = env->GetStaticMethodID(AnalyzeCidUtil, "add""(II)I"); 
  21.     if (NULL == sub) { 
  22.         env->DeleteLocalRef(AnalyzeCidUtil); // 删除类指引 
  23.         return -2; 
  24.     } 
  25.  
  26.     // 调用静态int方法 
  27.     int result = env->CallStaticIntMethod(AnalyzeCidUtil, add, x, y); 
  28.  
  29.     // 返回结果 
  30.     return result; 
  31.  
  32. /** 
  33.  * C回调Java方法(非静态) 
  34.  */ 
  35. int sub(JNIEnv *env, int x, int y) { 
  36.     // 获取类 
  37.     jclass AnalyzeCidUtil = env->FindClass("org/join/jni/JniTest"); 
  38.     if (NULL == AnalyzeCidUtil) { 
  39.         return -1; 
  40.     } 
  41.  
  42.     // 实例化类对象 
  43.     jobject mAnalyzeCidUtil = getInstance(env, AnalyzeCidUtil); 
  44.     if (NULL == mAnalyzeCidUtil) { 
  45.         env->DeleteLocalRef(AnalyzeCidUtil); // 删除类指引 
  46.         return -2; 
  47.     } 
  48.  
  49.     // 获取对象sub方法 
  50.     jmethodID sub = env->GetMethodID(AnalyzeCidUtil, "sub""(II)I"); 
  51.     if (NULL == sub) { 
  52.         env->DeleteLocalRef(AnalyzeCidUtil); // 删除类指引 
  53.         env->DeleteLocalRef(mAnalyzeCidUtil); // 删除类对象指引 
  54.         return -3; 
  55.     } 
  56.  
  57.     // 调用非静态int方法 
  58.     int result = env->CallIntMethod(mAnalyzeCidUtil, sub, x, y); 
  59.  
  60.     // 返回结果 
  61.     return result; 
  62.  
  63. /** 
  64.  * 实例化类对象 
  65.  */ 
  66. jobject getInstance(JNIEnv *env, jclass clazz) { 
  67.     // 获取构造方法 
  68.     jmethodID constructor = env->GetMethodID(clazz, """()V"); 
  69.     if (NULL == constructor) { 
  70.         return NULL; 
  71.     } 
  72.     // 实例化类对象 
  73.     return env->NewObject(clazz, constructor); 
 
         注意静态和非静态方法相差的实例化类对象的区别!
 
五、后记
         附件样例工程有两个,JavaJni是Java工程,JniDll_win32是VS2010工程。
         Java工程带了在我环境下编译的dll,可直接跑,但我相信大多数人都跑不通-_-!(在朋友电脑上曾试过,可能是Java不同版本的原因吧)

         总之不行或者非win32系统的话重新编译吧,源文件在JniDll_win32工程内都有。注意include Java安装目录下include文件夹内的头文件哦。VS2010的话,右键工程 -> Properties -> Configuration Properties -> C/C++ -> General -> Additional Include Directories内设置,如:%JAVA_HOME%\include;%JAVA_HOME%\include\win32。