注:本文大部分内容参考http://wenku.baidu.com/link?url=YLs988WKSwRQoV3sOGvhBhH3xALeaSNb17RB4-rQtMIrefRhRIZtBF8bYTAG4Jol0eFBkfjPRBDWikgyLo1bas4xfX4p6YpfexT_GmlWkEK和jni.h,在此基础上添加了一些自己的注释或新增了一些实例。
说明:
1. env参数是指向函数的列表的指针。在C中调用为(*env)->,在C++中调用为(env)->
2. 本地方法的obj 的意义取决于该方法是静态还是实例方法(static or an instance method)。当本地方法作为一个实例方法时,第二个参数相当于对象本身,即this. 当本地方法作为一个静态方法时,
指向所在类。
3. java中的String不管是中文还是英文,一个字符总是对应两个字节
4. Unicode 对应两个字节编码
5. UTF8对应一个字节编码
6. 变量的定义
typedef long jint;
typedef __int64 jlong;
typedef signed char jbyte;
typedef unsigned char jboolean;
typedef unsigned short jchar;
typedef short jshort;
typedef float jfloat;
typedef double jdouble;
typedef jint jsize;
————————–字符系列———————————————————-
1、函数原型:const char* (JNICALL *GetStringUTFChars)(JNIEnv *env, jstring str, jboolean *isCopy)
函数说明:用来取得某个jstring对象相关的Java字符串,把一个Unicode字串转成UTF-8格式字串
参数说明:
jstring str:传入一个指向java中的String对象的jstring变量
jboolean isCopy:传入一个jboolean的指针,是用来标识是否对java的String对象进行了拷贝。如果传入这个jboolean指针不是NULL,则它会给该指针所指向的内存传入JNI_TRUE或JNI_FALSE标识是否进行了拷贝。传入NULL表示不关心是否拷贝字符串,它就不会给jboolean指向的内存赋值。一般会把isCopy设为NULL,不关心Java VM对返回的指针是否直接指向java.lang.String的内容。一般不能预知VM是否会拷贝java.lang.String的内容,程序员应该假设GetStringChars会为java.lang.String分配内存。在JavaVM的实现中,垃圾回收机制会移动对象,并为对象重新配置内存。一旦java.lang.String占用的内存暂时无法被GC重新配置,将产生内存碎片,过多的内存碎片,会更频繁的出现内存不足的假象。
返回类型:char*
2、函数原型: void (JNICALL ReleaseStringUTFChars)(JNIEnv *env, jstring str, const char chars);
函数说明:来释放拷贝的内容
参数说明:
jstring str 指定一个jstring变量,即是要释放的本地字符串的来源
const char* chars 就是要释放的本地字符串
3、函数原型:const jchar *(JNICALL *GetStringChars)(JNIEnv *env, jstring str, jboolean *isCopy);
函数说明:用来取得某个jstring对象相关的Java字符串,以Unicode形式存储
参数说明: 参数和GetStringUTFChars函数参数意思一样
返回类型:jchar 两个字节
4、函数原型:void (JNICALL *Relea
seStringChars)(JNIEnv *env, jstring str, const jchar *chars);
函数说明:同ReleaseStringUTFChars
参数说明: 同ReleaseStringUTFChars
返回类型:void
5、函数原型:jsize (JNICALL *GetStringLength)(JNIEnv *env, jstring str);
函数说明:获得以Unicode编码的字串长度
参数说明: jstring str Java 传进来的字符串对象
返回类型:Java中String对象中字符的个数
6、函数原型: jsize (JNICALL *GetStringUTFLength)(JNIEnv *env, jstring str);
函数说明:获得以UTF8编码的字串长度
参数说明: jstring str Java 传进来的字符串对象
返回类型:Java中String对象中字符的个数
7、函数原型:void GetStringUTFRegion(JNIEnv *env,jstring str, jsize start, jsize len, char *buf)
函数说明:拷贝Java字符串并以UTF-8编码传入buffer。把java字符串的内容直接拷贝到C/C++的字符数组中。
在呼叫这个函数之前必须有一个C/C++分配出来的字符串,然后传入到这个函数中进行字符串的拷贝(此函数不分配内存)
参数说明:jstring str Java 传进来的字符串对象
jsize start Java 传进来的字符串对象复制的起始地址
jsize len 复制的数据长度
char *buf 存放数据的buf
返回类型:void
8、函数原型:void GetStringRegion(JNIEnv env,jstring str, jsize start,jsize len,jchar buffer);
函数说明:拷贝java字符串并以UTF-16编码传入buffer
函数说明:同GetStringUTFRegion
参数说明: 同GetStringUTFRegion
返回类型:void
9、函数原型:jstring NewString(JNIEnv env,const jchar str,jsize len);
函数说明:在C/C++本地代码中创建JAVA的String字符串对象
参数说明:const jchar* str 在C中创建的jstring对象
jsize len 组建字符的长度值,从0开始组建
返回类型:jstring
10、函数原型:jstring NewStringUTF(const char * str);
函数说明:在C/C++本地代码中创建JAVA的String字符串对象
参数说明:const char* str 在C中创建的jstring对象
jsize len 组建字符的长度值,从0开始组建
返回类型:jstring
以上函数所用实例:
C语言实现:
JNIEXPORT jstring JNICALL Java_com_tz_test_NativeTest_getCountFromC
(JNIEnv * env , jclass obj,jstring str)
{
//相当于把str转为两字节的Unicode编码
const jchar* getStr = (*env)->GetStringChars(env,str,NULL);
LOGI("getStrData==%s",getStr);
jsize strSize = (*env)->GetStringLength(env,str);
LOGI("getStrData==%d",strSize);
//ReleaseStringChars告诉JVM这个Chars字符串即getCStr不会被使用了,因为getCStr占用的内存会被回收。
(*env)->ReleaseStringChars(env,str,getStr);
//相当于把str转为单字节的UTF编码
const char *getCStr = (*env)->GetStringUTFChars(env,str,NULL);
LOGI("getCStrData==%s",getCStr);
jsize strCSize = (*env)->GetStringUTFLength(env,str);
LOGI("getCStrData==%d",strCSize);
//要使用ReleaseStringUTFChars 告诉JVM这个UTF-8字符串即getCStr不会被使用了,因为getCStr占用的内存会被回收。
(*env)->ReleaseStringUTFChars(env,str,getCStr);
//注意:GetStringUTFRegion和GetStringRegion这两个函数由于内部没有分配内存,
//所以JNI没有提供ReleaseStringUTFRegion和ReleaseStringRegion这样的函数
//GetStringUTFRegion这个函数会做越界检查,如果检查发现越界了,会抛出StringIndexOutOfBoundsException异常,
//这个方法与GetStringUTFChars比较相似,不同的是,GetStringUTFRegion内部不分配内存,不会抛出内存溢出异常。
//分别表示获取Unicode和UTF-8编码字符串指定范围内的内容
char outBuf [10] ;
//将JVM中的字符串以utf-8编码拷入C缓冲区,该函数内部不会分配内存空间
(*env)->GetStringUTFRegion(env,str,0,10,outBuf);
LOGI("getOutCStrData==%s",outBuf);
jchar outJBuf [10];
//将JVM中的字符串以Unicode编码拷入C缓冲区,该函数内部不会分配内存空间
(*env)->GetStringRegion(env,str,0,10,outJBuf);
//从getStr中取出5个unicode长度构建成jstring
jstring jstr = (*env)->NewString(env,getStr,5);
//把cjstring构建成jstring
const char * cjstring = "getstringfromC";
jstr = (*env)->NewStringUTF(env,cjstring);
return jstr;
}
字符串操作总结:
1、对于小字符串来说,GetStringRegion和GetStringUTFRegion这两对函数是最佳选择,因为缓冲区可以被编译器提前分配,
而且永远不会产生内存溢出的异常。当你需要处理一个字符串的一部分时,使用这对函数也是不错。因为它们提供了一个开
始索引和子字符串的长度值。另外,复制少量字符串的消耗也是非常小的。
2、获取Unicode字符串和长度,使用GetStringChars和GetStringLength函数
3、获取UTF-8字符串的长度,使用GetStringUTFLength函数
4、创建Unicode字符串,使用NewString函数
5、从Java字符串转换成C/C++字符串,使用GetStringUTFChars函数
6、通过GetStringUTFChars、GetStringChars、GetStringCritical获取字符串,这些函数内部会分配内存,必须调用相对应的
ReleaseXXXX函数释放内存
//——————–数组系列—————————————————————————–
1、函数原型:jbyte * (JNICALL *GetByteArrayElements)(JNIEnv *env, jbyteArray array, jboolean *isCopy);
函数说明 将Java中的byte数组转换成JNI中的基本类型,并由该类型的指针指向第一个元素
参数说明:jbyteArray array,Java中的byte数组
jboolean *isCopy 同字符函数的isCopy
返回类型 jbyte *
2、函数原型:void (JNICALL *ReleaseByteArrayElements)(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode)
函数说明:释放分配的jbyte数组
参数说明:jbyteArray array Java中的byte数组
jbyte *elems 由GetByteArrayElements函数分配的空间
jint mode 释放模式 一般给0
3、函数原型:jsize (JNICALL *GetArrayLength)(JNIEnv *env, jarray array);
函数说明:获得数组元素的个数
参数说明:jarray array Java数组的对象
返回类型: jsize 数组元素个数
4、函数原型:void (JNICALL *GetByteArrayRegion)(JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);
函数说明:将jbyteArray数组拷贝到buf中
参数说明:jbyteArray array 生成的jbyteArray 数组,可以使Java传递的,也可以使jni中自己生成
jsize start jbyteArray数组的起始地址
jsize 要拷贝的数据长度
jbyte buf 待存放数据的 jbyte buf
返回类型 void
5、函数原型:void (JNICALL *SetByteArrayRegion)(JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);
函数说明:将 buf数组中的值拷贝到jbyteArray数组中
参数说明:jbyteArray array 生成的jbyteArray 数组,可以使Java传递的,也可以使jni中自己生成
jsize start jbyteArray数组的起始地址, 从buf的首地址开始复制
jsize 要拷贝的数据长度
jbyte buf 待存放数据的 jbyte buf
返回类型 void
6、函数原型:jbyteArray (JNICALL *NewByteArray)(JNIEnv *env, jsize len);
函数说明:生成一个jbyteArray型数组(一维数组)
参数说明:jsize len 生成数组的大小
返回类型:jbyteArray 数组
7、还有其它类型生成的一维数组
1> jbooleanArray (JNICALL *NewBooleanArray)(JNIEnv *env, jsize len);
2> jbyteArray (JNICALL *NewByteArray)(JNIEnv *env, jsize len);
3> jcharArray (JNICALL *NewCharArray)(JNIEnv *env, jsize len);
4> jshortArray (JNICALL *NewShortArray)(JNIEnv *env, jsize len);
5> jintArray (JNICALL *NewIntArray)(JNIEnv *env, jsize len);
6> jlongArray (JNICALL *NewLongArray)(JNIEnv *env, jsize len);
7> jfloatArray (JNICALL *NewFloatArray)(JNIEnv *env, jsize len);
8> jdoubleArray (JNICALL *NewDoubleArray)(JNIEnv *env, jsize len);
9> jobjectArray (JNICALL *NewObjectArray)(JNIEnv *env, jsize len, jclass clazz, jobject init);
C++实例:
static int JNICALL com_notioni_uart_manager_TtyNativeControl__sendMsgToTty(JNIEnv *env,jobject clazz,jbyteArray data){//byte[]
LOGW("com_notioni_uart_manager_TtyNativeControl__sendMsgToTty");
//jbyte * arrayBody = env->GetByteArrayElements(data,0); jsize theArrayLengthJ = env->GetArrayLength(data); BYTE * starter = (BYTE *)arrayBody;
if(mTtyfd < 0){
LOGE("mTtyfd open failure ,non't write");
return -1;
}
jbyte* arrayData = (jbyte*)env->GetByteArrayElements(data,0);
jsize arrayLength = env->GetArrayLength(data);
char* byteData = (char*)arrayData;
int len = (int)arrayLength;
// LOGW("write data len:%d",len);
// LOGW("write data:%s",byteData);
int re = write(mTtyfd,byteData,len);
if(re == -1){
LOGE("write device error");
}
//释放GetByteArrayElements申请的资源
env->ReleaseByteArrayElements(env, data, arrayData, 0);
return re;
}
还有和jbyteArray一样的其它类型的数组,用法一致
jbooleanArray GetBooleanArrayElements
jbyteArray GetByteArrayElements
jcharArray GetCharArrayElements
jshortArray GetShortArrayElements
jintArray GetIntArrayElements
jlongArray GetLongArrayElements
jfloatArray GetFloatArrayElements
jdoubleArray GetDoubleArrayElements
jobjectArray GetObjectArrayElement