Skip to content

字符串的使用

前面我们知道如何使用基本数据类型,本文我们来看如何将字符串传入和传出本地(native)方法。

我们先来看一个返回String的例子,分别看kotlin代码与cpp代码。

class Jerry {
    companion object {
        init {
            System.loadLibrary("fisher-pole")
        }
    }
    external fun name(): String?
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_rustfisher_fishpole_worker_Jerry_name(JNIEnv *env, jobject thiz) {
    std::string jerry = "Jerry";
    return env->NewStringUTF(jerry.c_str());
}

在c++代码中,我们调用了env->NewStringUTF();方法来获得jstring

调用方法的写法是:env->再加上具体的方法。

NewStringUTF函数可以用来构造一个新的jstring,而读取现有jstring对象的内容,需要使用GetStringUTFChars函数。 该函数返回指向描述字符串的“改良UTF-8”字符的 const jbyte* 指针。

注意,具体的虚拟机可以为其内部的字符串表示自由选择编码机制。

所以,你可以得到实际的Java字符串的字符指针。

因为Java字符串是不可变的,所以慎重处理const就显得非常重要,不要试图将数据写到该字符数组中。另一方面,如果虚拟机使用UTF-16或UTF-32字符作为其内部字符串的表示,那么该函数会分配一个新的内存块来存储等价的“改良UTF-8”编码字符。

虚拟机必须知道你何时使用完字符串,这样它就能进行垃圾回收(垃圾回收器是在一个独立线程中运行的,它能够中断本地方法的执行)。基于这个原因,你必须调用ReleaseStringUTFChars函数。

另外,可以通过调用GetStringRegionGetStringUTFRegion方法来提供你自己的缓存,以存放字符串的字符。 最后GetStringUTFLength函数返回字符串的“改良UTF-8”编码所需的字符个数。

倒序字符串的例子

有了上面的知识后,我们来尝试把输入的字符串倒序输入。

首先准备native方法,在kotlin代码增加reverseString方法

class Jerry {
    companion object {
        init {
            System.loadLibrary("fisher-pole")
        }
    }
    external fun reverseString(input: String): String?
}

编写C++实现,在jerry.cpp中增加代码

extern "C"
JNIEXPORT jstring JNICALL
Java_com_rustfisher_fishpole_worker_Jerry_reverseString(JNIEnv *env, jobject thiz, jstring input) {
    const char *inputPtr = env->GetStringUTFChars(input, NULL);
    int len1 = env->GetStringLength(input);
    int len2 = strlen(inputPtr);

    char *out = new char[len1 + 1]{}; // 这里需要多一位
    for (int i = 0; i < len1; i++) {
        out[i] = inputPtr[len1 - i - 1];
    }
    jstring res = env->NewStringUTF(out);

    delete[] out;
    env->ReleaseStringChars(input, reinterpret_cast<const jchar *>(inputPtr));

    return res;
}

len1len2其实是一样的。两种方法获取传入字符串的长度。

首先拿到传入的jstring的内容,用env->GetStringUTFChars方法。获得一个const char指针。

然后新分配一个char数组,拿来存放倒序后的内容。

env->NewStringUTF新建一个jstring,就是我们要的结果。

最后回收资源,并返回结果。

实际项目中,并不会这么做,这只是个示例。

代码在这 https://github.com/AnRFDev/Tutorial2020