jni 调用java代码

1.创建java对象

首先在java端自定义一个Person类如下

Java代码   收藏代码
  1. package com.example;  
  2.   
  3. public class Person {  
  4.       
  5.     public String name;  
  6.       
  7.     public int age;  
  8.       
  9.     public Person()  
  10.     {  
  11.           
  12.     }  
  13.     public Person(String name,int age)  
  14.     {  
  15.         this.name=name;  
  16.         this.age=age;  
  17.     }  
  18.       
  19.   
  20.     public void Desc()  
  21.     {  
  22.         System.out.println("姓名: "+this.name+" 年龄:"+this.age);  
  23.     }  
  24.       
  25.   
  26. }  

 定义本地方法sayHello方法,在sayHello方法里实现创建Person对象,并调用创建对象的Desc()方法

Java代码   收藏代码
  1. package com.example;  
  2.   
  3.   
  4. public class jni_test {  
  5.   
  6.     //在本地方法sayHello里里创建Person对象  
  7.     public native void sayHello();  
  8.       
  9.   
  10.     static{  
  11.         System.loadLibrary("NativeCode");  
  12.     }  
  13.       
  14.     public static void main(String[] args) {  
  15.           
  16.         jni_test temp=new jni_test();  
  17.           
  18.         temp.sayHello();  
  19.     }  
  20.           
  21. }  

 

jni中创建java对象需要使用NewObject方法,jni里定义构造函数的名称为<init>,返回值为Void


1.调用默认构造函数创建Person对象

Cpp代码   收藏代码
  1. JNIEXPORT void JNICALL Java_com_example_jni_1test_sayHello(JNIEnv * evn, jobject obj)  
  2. {  
  3.     //获取java的Class  
  4.     jclass my_class=evn->FindClass("com/example/Person");  
  5.     //获取java的Person构造方法id---构造函数的函数名为<init>,返回值为void  
  6.     jmethodID init_id=evn->GetMethodID(my_class,"<init>","()V");//(类,属性名.签名)  
  7.     //创建Person对象--使用NewObject方法  
  8.     jobject person=evn->NewObject(my_class,init_id);  
  9.     //为person赋值  
  10.     jfieldID name_id=evn->GetFieldID(my_class,"name","Ljava/lang/String;");  
  11.     evn->SetObjectField(person,name_id,(evn)->NewStringUTF("mike"));  
  12.       
  13.     jfieldID age_id=evn->GetFieldID(my_class,"age","I");  
  14.     evn->SetIntField(person,age_id,20);  
  15.       
  16.     //获取Person的Desc方法id  
  17.      jmethodID desc_id=evn->GetMethodID(my_class,"Desc","()V");  
  18.   
  19.      //调用创建的person里的desc方法  
  20.     evn->CallVoidMethod(person,desc_id);  
  21.       
  22. }  

 运行结果:



 

2.调用有参构造方法,构造对象时完成对象属性赋值

 

Cpp代码   收藏代码
  1. JNIEXPORT void JNICALL Java_com_example_jni_1test_sayHello(JNIEnv * evn, jobject obj)  
  2. {  
  3.     //获取java的Class  
  4.     jclass my_class=evn->FindClass("com/example/Person");  
  5.     //获取java的Person构造方法id---构造函数的函数名为<init>,返回值为void  
  6.     jmethodID init_id=evn->GetMethodID(my_class,"<init>","(Ljava/lang/String;I)V");//(类,属性名.签名)      
  7.   
  8.     //创建Person对象--使用NewObject方法  
  9.     jobject person=evn->NewObject(my_class,init_id, (evn)->NewStringUTF("mike"),20);  
  10.       
  11.     //获取Person的Desc方法id  
  12.      jmethodID desc_id=evn->GetMethodID(my_class,"Desc","()V");  
  13.   
  14.      //调用创建的person里的desc方法  
  15.     evn->CallVoidMethod(person,desc_id);  
  16.       
  17. }  

 运行结果:



 

2.jni和java中文乱码

如果把创建Person对象改为

     jobject person=evn->NewObject(my_class,init_id, (evn)->NewStringUTF("珍奇异"),20)

 

此时运行结果产生了中文乱码:



 

乱码产生原因

java内部是使用16bit的unicode编码(UTF-16)来表示字符串的,无论中文英文都是2字节;jni内部是使用UTF-8编码来表示字符串的,UTF-8是变长编码的unicode,一般ascii字符是1字节,中文是3字节;

 

1、java --> c/c++

这种情况中,java调用的时候使用的是UTF-16编码的字符串,jvm把这个字符串传给jni,c/c++得到的输入是jstring,这个时 候,可以利用jni提供的两种函数,一个是GetStringUTFChars,这个函数将得到一个UTF-8编码的字符串;另一个是 GetStringChars这个将得到UTF-16编码的字符串。

 

2、c/c++ --> java

jni返回给java的字符串,c/c++首先应该负责把这个字符串变成UTF-8或者UTF-16格式,然后通过NewStringUTF或者NewString来把它封装成jstring,返回给java就可以了。

解决方法

方法一:使用#include <windows.h>头文件函数

导入头文件#include <windows.h>  ,此时有利用两个函数来处理字符串

Cpp代码   收藏代码
  1. //将jstring类型转换成windows类型  
  2. char* jstringToWindows( JNIEnv  *env, jstring jstr )  
  3. {  
  4.     int length = (env)->GetStringLength(jstr );  
  5.     const jchar* jcstr = (env)->GetStringChars(jstr, 0 );  
  6.     char* rtn = (char*)malloc( length*2+1 );  
  7.     int size = 0;  
  8.     size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), NULL, NULL );  
  9.     if( size <= 0 )  
  10.         return NULL;  
  11.     (env)->ReleaseStringChars(jstr, jcstr );  
  12.     rtn[size] = 0;  
  13.     return rtn;  
  14. }  
  15. //将windows类型转换成jstring类型  
  16. jstring WindowsTojstring( JNIEnv* env, char* str )  
  17. {  
  18.     jstring rtn = 0;  
  19.     int slen = strlen(str);  
  20.     unsigned short * buffer = 0;  
  21.     if( slen == 0 )  
  22.         rtn = (env)->NewStringUTF(str );   
  23.     else  
  24.     {  
  25.         int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );  
  26.         buffer = (unsigned short *)malloc( length*2 + 1 );  
  27.         if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )  
  28.             rtn = (env)->NewString(  (jchar*)buffer, length );  
  29.     }  
  30.     if( buffer )  
  31.         free( buffer );  
  32.     return rtn;  
  33. }  

 


此时把本地完整代码为:

Cpp代码   收藏代码
  1. #include"com_example_jni_test.h"  
  2. #include<iostream>  
  3. #include <windows.h>    
  4. using namespace std;  
  5.   
  6. //将windows类型转换成jstring类型  
  7. jstring WindowsTojstring( JNIEnv* env, char* str )  
  8. {  
  9.     jstring rtn = 0;  
  10.     int slen = strlen(str);  
  11.     unsigned short * buffer = 0;  
  12.     if( slen == 0 )  
  13.         rtn = (env)->NewStringUTF(str );   
  14.     else  
  15.     {  
  16.         int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );  
  17.         buffer = (unsigned short *)malloc( length*2 + 1 );  
  18.         if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )  
  19.             rtn = (env)->NewString(  (jchar*)buffer, length );  
  20.     }  
  21.     if( buffer )  
  22.         free( buffer );  
  23.     return rtn;  
  24. }  
  25.   
  26.   
  27. JNIEXPORT void JNICALL Java_com_example_jni_1test_sayHello(JNIEnv * evn, jobject obj)  
  28. {  
  29.     //获取java的Class  
  30.     jclass my_class=evn->FindClass("com/example/Person");  
  31.     //获取java的Person构造方法id---构造函数的函数名为<init>,返回值为void  
  32.       
  33.     jmethodID init_id=evn->GetMethodID(my_class,"<init>","(Ljava/lang/String;I)V");//(类,属性名.签名)      
  34.     //创建Person对象--使用NewObject方法  
  35.     jobject person=evn->NewObject(my_class,init_id, WindowsTojstring(evn,"珍奇异"),20);  
  36.       
  37.       
  38.     //获取Person的Desc方法id  
  39.     jmethodID desc_id=evn->GetMethodID(my_class,"Desc","()V");  
  40.   
  41.     //调用创建的person里的desc方法  
  42.     evn->CallVoidMethod(person,desc_id);  
  43.       
  44. }  

 运行结果:



 

方法二:

完整c++代码:

Java代码   收藏代码
  1. #include"com_example_jni_test.h"  
  2. #include<iostream>  
  3. using namespace std;  
  4.   
  5. //检查是否含有中文  
  6. int isASCII(const char * chp)  
  7. {  
  8.     char ch;  
  9.     jboolean flag= 1;  
  10.     while(ch = *chp++){  
  11.         if(ch & 0x80){  
  12.             flag = 0;  
  13.             break;  
  14.         }  
  15.     }  
  16.     return flag;  
  17. }  
  18.   
  19. //jstring to char*  
  20. char* JstringToPchar(JNIEnv* env, jstring jstr, const char * encoding,jmethodID gmidStringGetBytes)  
  21. {  
  22.     char* rtn = NULL;  
  23.     jstring jencoding;  
  24.     jencoding=(env)->NewStringUTF(encoding);         
  25.     jbyteArray barr= (jbyteArray)(env)->CallObjectMethod(jstr, gmidStringGetBytes, jencoding);     
  26.     jsize alen = (env)->GetArrayLength(barr);  
  27.     jbyte* ba = (env)->GetByteArrayElements(barr, JNI_FALSE);  
  28.     if (alen > 0)  
  29.     {  
  30.         rtn = (char*)malloc( alen + 1);     
  31.         memcpy(rtn, ba, alen);  
  32.         rtn[alen] = 0;  
  33.     }  
  34.     (env)->ReleaseByteArrayElements(barr, ba, 0);  
  35.     return rtn;  
  36. }  
  37.   
  38. //char* to jstring  
  39. jstring PcharToJstring(JNIEnv* env, const char* pchar,const char * encoding,jclass gStringClass,jmethodID gmidStringInit)  
  40. {  
  41.     jstring jencoding;  
  42.     jbyteArray bytes = (env)->NewByteArray(strlen(pchar));  
  43.     env->SetByteArrayRegion(bytes, 0, strlen(pchar), (jbyte*)pchar);  
  44.     jencoding = env->NewStringUTF(encoding);  
  45.     return (jstring)(env)->NewObject(gStringClass, gmidStringInit, bytes, jencoding);  
  46.   
  47. }  
  48.   
  49. JNIEXPORT void JNICALL Java_com_example_jni_1test_sayHello(JNIEnv * evn, jobject obj)  
  50. {  
  51.     //获取java的Class  
  52.     jclass my_class=evn->FindClass("com/example/Person");  
  53.       
  54.     //获取java的String相关方法  
  55.     jclass str_class=evn->FindClass("java/lang/String");  
  56.     jmethodID Byte_id=evn->GetMethodID(str_class,"getBytes""(Ljava/lang/String;)[B");  
  57.     jmethodID Strinit_id=evn->GetMethodID(str_class,"<init>","([BLjava/lang/String;)V");  
  58.   
  59.     //生成防止乱码字符串--结果赋给result  
  60.     char *myTest = "珍奇异";  
  61.     jstring result;  
  62.     //没有中文的情况  
  63.     if(isASCII(myTest)) {  
  64.         result = evn->NewStringUTF(myTest);  
  65.     }   
  66.     else{  
  67.         result = PcharToJstring(evn,myTest,"gbk",str_class,Strinit_id);  
  68.         char *outbuf;  
  69.         outbuf = JstringToPchar(evn,result,"utf-8",Byte_id);  
  70.         result =  (evn)->NewStringUTF(outbuf);  
  71.         if(outbuf){  
  72.             free(outbuf);  
  73.         }  
  74.     }   
  75.     //获取java的Person构造方法id---构造函数的函数名为<init>,返回值为void  
  76.     jmethodID init_id=evn->GetMethodID(my_class,"<init>","(Ljava/lang/String;I)V");//(类,属性名.签名)      
  77.   
  78.     //创建Person对象--使用NewObject方法  
  79.     jobject person=evn->NewObject(my_class,init_id, result,20);  
  80.   
  81.     //获取Person的Desc方法id  
  82.     jmethodID desc_id=evn->GetMethodID(my_class,"Desc","()V");  
  83.   
  84.     //调用创建的person里的desc方法  
  85.     evn->CallVoidMethod(person,desc_id);  
  86.   
  87. }  

 

运行结果:



 





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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值