java中的中文字符使用的编码方式是根据系统默认编码方式,一般使用的是GB2312的编码方式,jni中的中文字符采用的是unicode的编码方式。所以在字符传递的时候会出现乱码情况。
java层向jni传递中文字符的时候,我们可以利用windows.h给我们封装好的函数来操作。
JniMain.java
public class JniMain {
static{
System.loadLibrary("JNI_Demo1");
}
//----------------------向jni层传递字符串--------------------
public native String chineseChars(String str);
//---------------------------------------------
public static void main(String[] args) {
JniMain jm = new JniMain();
String str = jm.chineseChars("德玛西亚");
System.out.println("java "+ str);
}
}
jni_impl.c
#include "stdafx.h"
#include "JniMain.h"
#include <string.h>
#include <Windows.h>
/*
* Class: JniMain
* Method: chineseChars
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_JniMain_chineseChars
(JNIEnv * env, jobject jobj, jstring in){
//iscp代表的是string转char的时候是否从新开辟的内存copy的一份
jboolean iscp;
char * c_str = (*env)->GetStringChars(env, in, &iscp);
if (iscp == JNI_TRUE)
{
printf("is copy: JNI_TRUE\n");
}
else if (iscp == JNI_FALSE)
{
printf("is copy: JNI_FALSE\n");
}
int length = (*env)->GetStringLength(env, in);
const jchar * jcstr = (*env)->GetStringChars(env, in, NULL);
if (jcstr == NULL) {
return NULL;
}
//jchar -> char
char * rtn = (char *)malloc(sizeof(char)* 2 * (length + 1));
memset(rtn, 0, sizeof(char)* 2 * (length + 1));
int size = 0;
//windows提供的字符串转码的操作
size = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)jcstr, length, rtn, sizeof(char)* 2 * (length + 1), NULL, NULL);
/*if (size <= 0)
{
printf("size: 0 \n", rtn);
return NULL;
}*/
printf("jni string: %s\n", rtn);
if (rtn != NULL) {
free(rtn);
rtn = NULL;
}
if (iscp == JNI_TRUE)
{
(*env)->ReleaseStringChars(env, in, c_str);// JVM 使用。通知JVM c_str 所指的空间可以释放了
}
return NULL;
}
jni_impl.c的JNICALL Java_JniMain_chineseChars函数是将java层传递的字符串能转换成jni能识别的字符串。执行结果:
jni层向java层传递字符串时可以使用JNIEnv所指向的结构体封装的函数来调用java中String对象封装的字符串转码功能。
jni_impl.c
#include "stdafx.h"
#include "JniMain.h"
#include <string.h>
#include <Windows.h>
/*
* Class: JniMain
* Method: chineseChars
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_JniMain_chineseChars
(JNIEnv * env, jobject jobj, jstring in){
char *c_str2 = "诺克萨斯";
jclass str_cls = (*env)->FindClass(env, "java/lang/String");
jmethodID jmid = (*env)->GetMethodID(env, str_cls, "" , "([BLjava/lang/String;)V");
//jstring -> jbyteArray
jbyteArray bytes = (*env)->NewByteArray(env, strlen(c_str2));
// 将Char * 赋值到 bytes
(*env)->SetByteArrayRegion(env, bytes, 0, strlen(c_str2), c_str2);
jstring charsetName = (*env)->NewStringUTF(env, "GB2312");
return (*env)->NewObject(env, str_cls, jmid, bytes, charsetName);
}
其实上面的代码就是jvm反射调用java中的 new String(“诺克萨斯”,“GB2312”)