java jni 入门3 - 字符串参数

来源:互联网 发布:linux查看应用占用内存 编辑:程序博客网 时间:2024/06/05 18:52

参考:《Java核心技术 卷II:高级特性》第12章 本地方法


##################################################################


Java编程语言中的字符串是UTF-16编码点的序列,而C的字符串则是以null结尾的字节序列,所以在这两种语言中的字符串是不一样的。Java本地接口有两组操作字符串的函数,一组把Java字符串转换成"改良的UTF-8"字节序列,另一组将它们转换成UTF-16数值的数组,也就是说转换成jchar数组。


如果你的C代码已经使用了Unicode,你可以使用第二组转换函数。

另一方面,如果你的字符串都仅限于ASCII字符,你可以使用"改良的UTF-8"转换函数


带有字符串参数的本地方法实际上都要接受一个jstring类型的值。带有字符串参数返回值的本地方法必须返回一个jstring类型的值。JNI函数将读入并构造出这些jstring对象。

例如,NewStringUTF函数从包含ASCII字符的字符数组创建一个新的jstring对象,或者是更一般的“改良的UTF-8”编码的字节序列。(使用NewStringUTF方法即可

以下是对NewStringUTF函数的一个调用:

JNIEXPORT jstring JNICALL Java_HelloNative_getGreeting(JNIEnv *env, jclass cl) {jstring jstr;char greeting[] = "Hello, Native World!";jstr = (*env)->NewStringUTF(env, greeting);return jstr;}

所有对JNI函数的调用都使用到了env指针,该指针是每一个本地方法的第一个参数。env指针是函数指针表的指针。所以,必须在每个JNI调用前面加上(*env)->,以便实际上取消对函数指针的引用。而且,env是每个JNI函数的第一个参数。

note:C++中对JNI函数的访问要简单一些。JNIEnv类的C++版本有一个内联成员函数,它负责帮你查找函数指针。故调用方式为:

jstr = env->NewStringUTF(greeting)
注意,这里从该调用的参数列表里删掉了JNIEnv指针

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

note:具体的虚拟机可以自由地选择该编码来表示它内部的字符串。所以,你可以得到实际的Java字符串的字符指针。因为Java字符串是不可变的,所以慎重处理const就显得非常重要,不要试图将数据写到该字符数组中

另一方面,如果虚拟机使用UTF-16或UTF-32字符作为其内部字符串的表示,那么该函数会分配一个新的内存来存储等价的“改良UTF-8”编码字符。


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

另外,可以通过调用GetStringRegion或GetStringUTFRegion方法来提供自己的缓存,以存放字符串的字符。

函数GetStringUTFLength函数返回编码字符串所需的"改良UTF-8"字符个数


以C代码访问Java字符串

jstring NewStringUTF(JNIEnv *env, const char bytes[])
根据以全0字节结尾的“改良UTF-8”字节序列,返回一个新的Java字符串对象,或者当字符串无法构造时,返回NULL


jsize GetStringUTFLength(JNIEnv *env, jstring string)

返回进行UTF-8编码所需的字节个数(不计算作为终止符的全0字节)


const jbyte* GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy)
返回"改良UTF-8"编码的字符串的指针,或者当不能构建字符数组时返回NULL。直到ReleaseStringUTFChars函数调用前,该指针一直有效。isCopy指向一个jboolean,如果进行了复制,则填入JNI_TRUE,否则填入JNI_FALSE


void ReleaseStringUTFChars(JNIEnv *env, jstring string, const jbyte bytes[])
通知虚拟机本地代码不再需要通过bytes(GetStringUTFChars返回的指针)返回Java字符串


void GetStringRegion(JNIEnv *env, jstring string, jsize start, jsize lengh, jchar *buffer)
将一个UTF-16双字节序列从字符串复制到用户提供的尺寸至少大于2xlength的缓存中。


void GetStringUTFRegion(JNIEnv *env, jstring string, jsize start, jsize length, jbyte *buffer)
将一个"改良UTF-8"字符序列从字符串复制到用户提供的缓存中。为了存放要复制的字节,该缓存必须足够长。最坏情况下,要复制3xlength个字节。


jstring NewString(JNIEnv* env, const jchar chars[], jsize length)
根据Unicode字符串返回一个新的Java字符对象,或者在不能创建时返回NULL

参数:env          JNI接口指针

           chars       以null结尾的UTF-16字符串

           length      字符串中字符的个数


jsize GetStringLength(JNIEnv *env, jstring string)
返回字符串中字符的个数。


const jchar* GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy)
返回Unicode编码的字符串的指针,或者当不能构建字符数组时返回NULL。直到ReleaseStringChars函数调用前,该指针一直有效。isCopy为NULL或者是指向JNI_TRUE填充的jboolean,否则,它指向JNI_FALSE填充的jboolean.


void ReleaseStringChars(JNIEnv *env, jstring string, const jchar chars[])
通知虚拟机本地代码不再需要通过chars(GetStringChars返回的指针)返回Java字符串。


##########################################################################################3


使用带有本地sprint方法的类

格式化浮点数的C函数原型如下:

JNIEXPORT jstring JNICALL Java_Printf2_sprint(JNIEnv *env, jclass cl, jstring format, jdouble x)

printf2Test.java

/** * @time 15-11-10 * @author zj**/class Printf2Test {public static void main(String[] args) {double price = 44.95;double tax = 7.75;double amountDue = price * (1 + tax / 100);String s = Printf2.sprint("Amount due = %8.2f", amountDue);System.out.println(s);}}

Printf2.java

/** * @time 15-11-10 * @author zj**/class Printf2 {public static native String sprint(String format, double x);static {System.loadLibrary("Printf2");}}

printf.c

/** * @time 15-11-10 * @author zj*/#include "Printf2.h"#include <stdio.h>#include <stdlib.h>#include <string.h>JNIEXPORT jstring JNICALL Java_Printf2_sprint  (JNIEnv *env, jclass cl, jstring format, jdouble x) {const char* cformat;jstring ret;cformat=(*env)->GetStringUTFChars(env, format, NULL);char* cret;cret = (char*)malloc(strlen(cformat)+8);sprintf(cret, cformat, x);ret = (*env)->NewStringUTF(env, cret);free(cret);(*env)->ReleaseStringUTFChars(env, format, cformat);return ret;}

注意,通过调用GetStringUTFChars来读取格式参数,通过调用NewStringUTF来产生返回值,通过调用ReleaseStringUTFChars来通知虚拟机不再需要访问字符串。





0 0
原创粉丝点击