Java 使用jni调用c++函数的步骤:
1.定义java类中的native方法,新建下面一个类
Java代码
1. publicclass NativeDemo {
2.
3. publicstaticnativevoid say(); //static的native方法
4.
5. publicnativevoid sayHello(); //实例的native方法,两者的处理不一样
6.
7. publicstaticint number = 10;
8.
9. int a = 2;
10.
11. publicvoid callThis(){
12. System.out.println("c++ call java method");
13. }
14.
15. publicstaticvoid main(String[] args) {
16. System.loadLibrary("NativeJni");
17. // NativeDemo.sayHello();
18. new NativeDemo().sayHello();
19. say();
20. }
21. }
2.进入java命令行
3.在vc++新建一个dll的控制台工程
4.在vc的工程里面导入刚才的那个NativeDemo.h的头文件,然后因为这个头文件需要引用jdk安装目录下的jni.h和jni_mt.h的两个头文件,从jdk的安装目录下的拷贝到工程里面
4.编写NativeDemo.h的头文件定义的两个类的实现(这里需要吧jni.hinclude的时候要改为“”,而不是<>,因为jni.h是在当前工程里面)
/*DO NOT EDIT THIS FILE - it is machine generated */
Cpp代码
1. #include "jni.h"
2. /* Header for class NativeDemo */
3.
4. #ifndef _Included_NativeDemo
5. #define _Included_NativeDemo
6. #ifdef __cplusplus
7. extern"C" {
8. #endif
9. /*
10. * Class: NativeDemo
11. * Method: say
12. * Signature: ()V
13. */
14. JNIEXPORT void JNICALL Java_NativeDemo_say
15. (JNIEnv *, jclass);
16.
17. /*
18. * Class: NativeDemo
19. * Method: sayHello
20. * Signature: ()V
21. */
22. JNIEXPORT void JNICALL Java_NativeDemo_sayHello
23. (JNIEnv *, jobject);
24.
25. #ifdef __cplusplus
26. }
27. #endif
28. #endif
c++源文件
#include"NativeDemo.h"
Cpp代码
1. #include "jni.h"
2. #include
3. usingnamespace std;
4.
5. JNIEXPORT void JNICALL Java_NativeDemo_say(JNIEnv * env, jclass jclazz) //static的方法生成的两个参数是JNIEnv * env, jclass jclazz,第二个参数代表java的类的class实例
6. {
7. jclass jclass_native = env->FindClass("NativeDemo"); //查找类的class对象,
8. jfieldID jfield_numberId = env->GetStaticFieldID(jclass_native,"number", "I"); //获得jclazz类的静态字段number,第三个参数代表静态变量的签名,java每种类型对应到一个签名串
9. jint jfield_number = env->GetStaticIntField(jclass_native, jfield_numberId);//获得jclazz类的静态变量的值
10. cout << jfield_number << endl; //打印静态变量的值
11.
12. }
13.
14. JNIEXPORT void JNICALL Java_NativeDemo_sayHello(JNIEnv *env, jobject jobj)//实例方法生成的第二个参数是jobject,代表某一个实例
15. {
16. jclass clazz = env->GetObjectClass(jobj); //获得实例jobj的class对象
17. jfieldID jfield_numberId = env->GetFieldID(clazz,"a", "I"); //获得这个实例的a实例变量
18. jint jfield_value = env->GetIntField(jobj,jfield_numberId); //获得这个实例的a实例变量的值
19. cout << jfield_value << endl;//打印这个实例的a实例变量的值
20. }
5.编译这个vc的工程,生成一个dll文件
6.在我的电脑属性里面设置环境变量path增加这个dll的目录,因为java需要从path变量找到这个dll的目录
7.打开eclipse,编写调用的main函数代码
publicclass NativeDemo {
Java代码
1. publicstaticnativevoid say(); //static的native方法
2.
3. publicnativevoid sayHello(); //实例的native方法,两者的处理不一样
4.
5. publicstaticint number = 10;
6.
7. int a = 2;
8.
9. publicvoid callThis(){
10. System.out.println("c++ call java method");
11. }
12.
13. publicstaticvoid main(String[] args) {
14. System.loadLibrary("NativeJni");
15. NativeDemo.sayHello();
16. new NativeDemo().sayHello();
17. say();
18. }
注:可以直接使用 System.load("E://NativeJni.dll");
执行这个main函数,结果如下
在java中需要使用System.loadLibrary("NativeJni");加载vc工程生成的dll文件,这里dll后缀不能加。
遇到的问题:
1.中文乱码的问题:在Java函数中传入一个中文字符的参数,调用c++那边的函数打印出来的是乱码.
原因是:java 中传入的参数的类型是jstring,c++没有办法处理这种类型的参数,需要转换成合法的windows了性的参数才可以
使用的函数代码如下:
1. char * JStringToWindows(JNIEnv * pJNIEnv, jstring jstr)
2. {
3. jsize len = pJNIEnv->GetStringLength(jstr);
4. const jchar * jcstr = pJNIEnv->GetStringChars(jstr, NULL);
5. int size = 0;
6. char * str = (char *)malloc(len * 2 + 1);
7. if ((size = WideCharToMultiByte(CP_ACP, 0, LPCWSTR(jcstr), len, str, len * 2 + 1, NULL, NULL)) == 0)
8. return NULL;
9. pJNIEnv->ReleaseStringChars(jstr, jcstr);
10. str[size] = 0;
11. return str;
12. }
具体的关于中文乱码的问题可以参考下面这篇文章:
http://developer.51cto.com/art/201112/310128.htm