您的位置:首页 > 编程语言 > Java开发

java jni 入门3 - 字符串参数

2015-11-10 20:38 579 查看
参考:《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来通知虚拟机不再需要访问字符串。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: