JNI字符串操做

在Java中,建立一个String对象的方式很是简单,并且可使用String类的各类方法很方便的操做字符串。然而在JNI中,虽然jstring类表示Java的String类,可是jstring并无提供任何函数来操做字符串。html

编码格式

对于一个字符串常量,例如"abc",在Java中是用一个String对象表示,而且表明UTF-16编码格式的字符串(也就是双字节编码)。而在JNI中,是用一个char类型指针来表示,编码格式却为modified UTF-8java

那么什么是modified UTF-8编码格式呢?其实它与UTF-8格式很是像,可是有点小小的差异c++

  • 空字符(值为0),在UTF-8中是用一个字节表示,然而在modified UTF-8中,是用两个字节表示。
  • 对于一个字节,两个字节,三个字节能够表示的字符,这两种编码是同样的
  • 对于须要用四个字节表示的字符,modified。 UTF-8使用的是两个三字节来实现的。

若是想了解UTF-8modified UTF-8编码格式,能够参考文末连接。数组

JNI中对字符串的操做的函数,都有针对这两个格式的版本。下面我对两种编码格式的字符串操做的函数作一个归纳性的讲解。bash

UTF-16字符串函数

NewString

jstring NewString(JNIEnv *env, const jchar *unicodeChars, jsize len);
复制代码

参数oracle

  • jchar *unicodeChars: 指向Unicode编码字符串的指针。
  • jsize len: 字符串的长度。

NewString使用Unicode编码的字符数组建立一个Java的String对象。app

使用NewString的关键就是必须使用Unicode编码的字符串,而这里的Unicode编码通常都是指UTF-16编码。可是如何获取这个UTF-16编码的字符串呢,这个超出本文讨论的范畴,可是在Android开发中,有一个String16的类,经过构造函数就能够把一个字符串常量转化为UTF-16编码的字符串。ide

GetStringLength

jsize GetStringLength(JNIEnv *env, jstring string);
复制代码

参数函数

  • jstring string: Java的String对象。

GetStringLength函数返回的字符串长度与Java的String返回的字符串的长度的是同样的,例如String s = "中国";,这个Java字符串长度为2,又例如String s = "China";,这个字符串长度为5。ui

GetStringChars

const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);
复制代码

参数

  • jstring string: Java的String对象
  • jboolean * isCopy: 若是isCopy不为NULL,而且函数生成的是字符串的拷贝,那么*isCopy的值为JNI_TRUE,若是没有生成拷贝,那么*isCopy值为JNI_FALSE

GetStringChars返回一个指向Unicode编码的字符数组的指针(指针可能为NULL)。这个指针可能指向原字符串的数组,也可能指向拷贝的字符数组,取决与虚拟机的实现。若是是生成拷贝,就须要释放本地字符串,须要使用ReleaseStringChars

ReleaseStringChars

void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);
复制代码

参数

  • jstring string: Java的String对象
  • jchar *chars: 指向由GetStringChars返回的Unicode编码的字符数组

ReleaseStringChars函数并非本身去释放本地字符串(若是发生拷贝),而是通知虚拟机本地代码再也不访问jchar *chars,而后虚拟机本身决定如何处理。

GetStringRegion

void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
复制代码

参数

  • jstring str: Java的String对象
  • jsize start: 拷贝的开始位置
  • jsize len: 拷贝的长度
  • jchar *buf: 拷贝的目标缓冲区

GetStringRegion函数从start开始,拷贝len长度的Unicode字符到buf中。

GetStringCritical & ReleaseStringCritical

const jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);
复制代码

Get/ReleaseStringCritical函数与Get/ReleaseStringChars函数在使用和功能上是同样的。也就是说,GetStringCritical函数可能返回一个指向原字符串的指针,或者返回一个指向源字符串的拷贝的指针,这取决与虚拟机实现。若是发生了拷贝,那么就须要ReleaseStringCritial来通知虚拟机本地进行释放操做。

modified UTF-8字符串函数

NewStringUTF

jstring NewStringUTF(JNIEnv *env, const char *bytes);
复制代码

NewStringUTF的第二个参数const char *bytesmodified UTF-8编码的字节数组。

modified UTF-8是JNI特有的格式,使用这种格式的字符串与虚拟机中使用的字符串同样。

JNI使用modified UTF-8编码来表示各类字符串类型,例以下面两行代码都是使用这种编码的字符串

const char * bytes1 = "中国";
const char * bytes2 = "China";
复制代码

因为建立的字符串常量默认就是modified UTF-8编码的,所以NewStringUTF也就是你们最经常使用的来获取Java的String对象的函数。

GetStringUTFLength

jsize GetStringUTFLength(JNIEnv *env, jstring string);
复制代码

参数

  • jstring string: Java的String对象

GetStringUTFLength函数返回一个modified UTF-8编码格式字符串的字节长度。

注意,GetStringUTFLength返回的是字节长度,而GetStringLength返回的字符长度。一个是强调字节,一个是强调字符,这是有却别的。例如对于一个Java的字符串String s = "中国"GetStringUTFLength返回的值为6,表明6个字节长度,而GetStringLength返回的值为2,表明2个字符长度。

GetStringUTFChars

const char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);
复制代码

参数

  • jstring string: Java的String对象
  • jboolean * isCopy: 若是isCopy不为NULL,而且若是函数对原字符串进行了拷贝,那么*isCopy的值为JNI_TRUE,若是没有发生拷贝,那么*isCopy的值为JNI_FALSE

GetStringUTFChars函数返回一个指向modified UTF-8编码的字节数组指针。

从参数isCopy能够看出,GetStringUTFChars函数返回的指向字节数组的指针,可能指向远字符串,也可能指向拷贝的字符串。若是一旦发生了拷贝,那么在不须要这个拷贝的时候,就须要进行释放,能够调用ReleaseStringUTFChars函数。

ReleaseStringUTFChars

void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);
复制代码

参数

  • jstring string: Java的String对象
  • const char *utf: 由GetStringUTFChars获取。

ReleaseStringUTFChars函数只是通知虚拟机,本地代码再也不访问const char *utf,以后的处理动做取决与虚拟机。

GetStringUTFRegion

void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, 
                        jsize len, char *buf);
复制代码

GetStringUTFRegion函数与GetStringRegion函数的参数是同样,不一样的是GetStringUTFRegion函数会把拷贝到缓冲区的字符从Unicode转化为modified UTF-8格式。

使用

通常状况下,咱们都选择使用JNI默认的modified UTF-8编码字符串,由于很方便,不须要转换编码。而若是必定要使用UTF-16编码字符串,那么就须要进行转换。

那么如何在JNI层更好的处理字符串呢?若是使用的是C++开发JNI,那么能够在JNI层使用string类来操做字符串,而若是使用C语言,那么不得不使用字符指针一步一步来处理。

例如,一个Java类中有一个native方法

public class Hello {
    native string getHelloFromJNI(String name);
}
复制代码

在JNI层对应的实现为

static jstring getHello(JNIEnv *env, jobject thiz, jstring name) {
    // 从Java的String对象转换为本地表示
    const char *c_name = env->GetStringUTFChars(name, NULL);
    // 使用C++的string进行字符串拼接
    string str("Hello, ");
    str.append(c_name);
    str.append("!");
    env->ReleaseStringUTFChars(name, c_name);
    // 建立Java的String对象并返回
    return env->NewStringUTF(str.c_str());
}
复制代码

参考

modified UTF-8编码

docs.oracle.com/javase/7/do…

Unicode(UTF-8, UTF-16等)编码

baike.baidu.com/item/Unicod…

相关文章
相关标签/搜索