JNI编程四:java跟JNI字符串传递

目录


前言

java中的中文字符使用的编码方式是根据系统默认编码方式,一般使用的是GB2312的编码方式,jni中的中文字符采用的是unicode的编码方式。所以在字符传递的时候会出现乱码情况。

一、java层向jni层传递中文字符串的转码操作

java层向jni传递中文字符的时候,我们可以利用windows.h给我们封装好的函数来操作。

JniMain.java

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

java 复制代码
#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层传递中文字符串的转码操作

jni层向java层传递字符串时可以使用JNIEnv所指向的结构体封装的函数来调用java中String对象封装的字符串转码功能。

jni_impl.c

java 复制代码
#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, "<init>", "([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")


相关推荐
偶是老李头5 天前
Android - NDK:在Jni中打印Log信息
android·jni·android ndk log·jni log
菠萝加点糖21 天前
Android JNI 设置环境变量
android·环境变量·jni
菠萝加点糖21 天前
Android 设置动态库依赖路径
android·动态库·jni
木亦汐丫1 个月前
【隐私计算篇】Java(JDK17)通过JNI实现调用C++动态链接库(.so)
java·开发语言·c++·性能优化·jni·动态链接库·隐私计算
路人甲ing..2 个月前
JNI回调用中不同线程的env无法找到正确的kotlin的class
android·开发语言·c++·kotlin·jni
阿迷创客4 个月前
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
android·android studio·jni·ndk
tmacfrank5 个月前
NDK 入门(四)—— 静态缓存与 Native 异常
c++·jni·ndk
还好一切都可以重来5 个月前
jni 开发 调用dll 函数的流程
java·dll·cpp·jni
菠萝加点糖6 个月前
Android CMakeLists.txt不同渠道加载对应目录动态库
android·cmake·jni