常量函数非常多,就整理一些常见的函数用例,我先例举常量函数,并做一些标注,最后通过一个实例来一一验证。
常量或参数说明:
- env参数是指向函数的列表的指针。在C中调用为(*env)->,在C++中调用为(env)->
- 本地方法的obj 的意义取决于该方法是静态还是实例方法(static or an instance method)。当本地方法作为一个实例方法时,第二个参数相当于对象本身,即this. 当本地方法作为一个静态方法时,指向所在类。
- java中的String不管是中文还是英文,一个字符总是对应两个字节
- Unicode 对应两个字节编码
- UTF8对应一个字节编码
- 变量的定义
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 *ReleaseStringChars)(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
实例验证:
JNIEXPORT jstring JNICALL Java_com_lu_jni_TestCUtils_pramaCallMethodReture
(JNIEnv * env ,jclass obj,jstring str){
const jchar* getStr = (*env)->GetStringChars(env,str,JNI_FALSE);
LOGE("===const jchar* getStrjchar*======getStrData==%s",getStr);
jsize strSize = (*env)->GetStringLength(env,str);
LOGE("==jsize strSize===========%d",strSize);
//void
(*env)->ReleaseStringChars(env,str,getStr);
const char *getCStr = (*env)->GetStringUTFChars(env,str,JNI_FALSE);
LOGE("=const char *getCStr======getCStrData==%s",getCStr);
jsize strCSize = (*env)->GetStringUTFLength(env,str);
LOGE("===jsize strCSize======getCStrData==%d",strCSize);
(*env)->ReleaseStringUTFChars(env,str,getCStr);
char outBuf [10] ;
//void
(*env)->GetStringUTFRegion(env,str,0,5,outBuf);
LOGE("==char outBuf [10]=======getOutCStrData==%s",outBuf);
jchar outJBuf[10];
//void
(*env)->GetStringRegion(env,str,0,5,outJBuf);
LOGE("==jchar outJBuf[10]=======getOutCStrData==%s",outJBuf);
jstring jstr = (*env)->NewString(env,getStr,5);
LOGE("==jstring jstr=======getStrData==%s",jstr);
const char * cjstring = "pramaCallMethodReture";
jstring jstr1 = (*env)->NewStringUTF(env,cjstring);
LOGE("==const char * cjstring=======getStrData==%s",jstr1);
return jstr;
}
数组系列常量函数
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、还有其它类型生成的一维数组
- jbooleanArray (JNICALL *NewBooleanArray)(JNIEnv *env, jsize len);
- jbyteArray (JNICALL *NewByteArray)(JNIEnv *env, jsize
- jcharArray (JNICALL *NewCharArray)(JNIEnv *env, jsize len);
- jshortArray (JNICALL *NewShortArray)(JNIEnv *env, jsize len);
- jintArray (JNICALL *NewIntArray)(JNIEnv *env, jsize len);
- jlongArray (JNICALL *NewLongArray)(JNIEnv *env, jsize len);
- jfloatArray (JNICALL *NewFloatArray)(JNIEnv *env, jsize len);
- jdoubleArray (JNICALL *NewDoubleArray)(JNIEnv *env, jsize len);
- jobjectArray (JNICALL *NewObjectArray)(JNIEnv *env, jsize len, jclass clazz, jobject init);
实体验证:
JNIEXPORT jstring JNICALL Java_com_lu_jni_TestCUtils_testArray
(JNIEnv * env, jobject obj, jbyteArray bdata){
jint i = 0 ;
//将Java中的byte数组转换成JNI中的基本类型,并由该类型的指针指向第一个元素
jbyte *jByte = (*env)->GetByteArrayElements(env,bdata,NULL);
//获得数组元素的个数
jsize len = (*env)->GetArrayLength(env,bdata);
LOGE("arrary len = %d",len);
/*
* JNI 程序开发者要遵循 native 语言本身的内存管理机制,避免造成内存泄漏。
* 以 C 语言为例,当用 malloc() 在进程堆中动态分配内存时,JNI 程序在使用完后,应当调用 free() 将内存释放。
*/
/*
* malloc函数是一种分配长度为num_bytes字节的内存块的函数,可以向系统申请分配指定size个字节的内存空间。
* malloc的全称是memory allocation,中文叫动态内存分配,当无法知道内存具体位置的时候,
* 想要绑定真正的内存空间,就需要用到动态的分配内存。
*/
//unsigned无符号型 字符数组
//类型名称 字节数 取值范围
//unsigned char 1 0~255
unsigned char *cBuf = (unsigned char *)malloc(len);
/*memset()函数原型是extern void *memset(void *buffer, int c, int count)
* buffer:为指针或是数组,
* c:是赋给buffer的值,
* count:是buffer的长度.
*/
/*
* 作用:
* 这个函数在socket中多用于清空数组.如:原型是memset(buffer, 0, sizeof(buffer))
* Memset 用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ’或‘/0’;
* 例:char a[100];memset(a, '/0', sizeof(a));
* memset可以方便的清空一个结构类型的变量或数组。
*/
//memset() 函数常用于内存空间初始化。
memset(cBuf,0,len);
//memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度。
memcpy(cBuf,jByte,len);
jbyte *buf = (jbyte * )malloc(len);
//另外一种方法 将bdata数组拷贝到buf中
(*env)->GetByteArrayRegion(env,bdata,0,len,buf);
//生成一个jbyteArray型数组(一维数组)
jbyteArray byteBuf = (*env)->NewByteArray(env,len);
//将 buf数组中的值拷贝到jbyteArray数组中
//(*env)->SetByteArrayRegion(env,byteBuf,0,len,buf);
(*env)->SetByteArrayRegion(env,byteBuf,2,len-5,buf);//从第二开始取值(包括第二个)往后取4个,其他的补0
//将Java中的byte数组转换成JNI中的基本类型,并由该类型的指针指向第一个元素
jByte = (*env)->GetByteArrayElements(env,byteBuf,NULL);
for(i = 0 ; i < len; i++)
{
LOGE("=======%d",jByte[i]);
}
(*env)->ReleaseByteArrayElements(env, bdata, jByte, 0);
const char * cjstring = "test array success !";
jstring jstr = (*env)->NewStringUTF(env,cjstring);
return jstr;
}
还有和jbyteArray一样的其它类型的数组,用法一致
jbooleanArray
jbyteArray
jcharArray
jshortArray
jintArray
jlongArray
jfloatArray
jdoubleArray
jobjectArray
在jni中调用Java中的方法的函数
类型签名:
签名是一种用参数个数和类型区分同名方法的手段,即解决方法重载问题。
其中要特别注意的是:
- 类描述符开头的'L'与结尾的';'必须要有 String类型的签名是“Ljava/lang/String;”
- 数组描述符,开头的'['必须有.
- 方法描述符规则:" (各参数描述符)返回值描述符",其中参数描述符间没有任何分隔
符号
类型签名 Java类型 C类型
V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short
数组则以"["开始,用两个字符表示
[I jintArray int[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]
[D jdoubleArray double[]
[J jlongArray long[]
[Z jbooleanArray boolean[]
1、
函数原型:jclass (JNICALL *GetObjectClass)(JNIEnv *env, jobject obj);
函数说明:函数得到该对像的类,该函数返回一个jclass类型值,其中obj参数表示要你想要得到类型的类对象。通过该方法可以获取到调用该方法的对象所在的类
参数说明:见开头
返回类型:jclass
2、
函数原型:jclass (JNICALL *FindClass)(JNIEnv *env, const char *name);
函数说明:功能同GetObjectClass,但是在访问静态域的时候必须使用FindClass,而不能使用GetObjectClass。
在FindClass()的第二个参数是类的编码签名,类的编码签名和 基本类型的编码签名有所不同,
如果类在当前包中,就直接是类的名称,如果类不在当前包中则要加入该类的详细路径:
例如String类在java.lang 包中,则String的签名要写成( Ljava/lang/String;),
其中的(L和;)是不可少的,其中(;)是表达是的终止符
参数说明:const char *name:类全名(即包名后跟类名,之间由“/”分隔)。如果该名称以“[”(数组签名字符)打头,则返回一个一维数组类。
返回类型:jclass
3、
函数原型:jfieldID (JNICALL *GetFieldID)(JNIEnv *env, jclass clazz, const char *name, const char *sig);
函数说明:获取实例域的ID
参数说明:const char *name Java中定义的实例域的名称
const char *sig 实例域的类型签名
jclass clazz 获取到的类
返回类型:jfieldID
4、
函数原型:jobject (JNICALL *GetObjectField)(JNIEnv *env, jobject obj, jfieldID fieldID);
函数说明:获取到域ID的内容,Java的String类型,要用GetObjectField函数获取,这里提示大家没有
GetStringField这样的函数在JNI中,或者说在C语言中
参数说明:jfieldID fieldID 有效的域ID
jobject obj Java中传下来的类对象
返回类型:域内容
5、
函数原型:jint (JNICALL *GetIntField)(JNIEnv *env, jobject obj, jfieldID fieldID);
函数说明:获取整型实例域的内容
参数说明:jfieldID fieldID 有效的域ID
jobject obj Java中传下来的类对象
返回类型:jint
6、
还有其它类型的获取实例域的内容函数用法和GetIntField方法使用一样,
1. jboolean (JNICALL *GetBooleanField)(JNIEnv *env, jobject obj, jfieldID fieldID);
2. jbyte (JNICALL *GetByteField)(JNIEnv *env, jobject obj, jfieldID fieldID);
3. jchar (JNICALL *GetCharField)(JNIEnv *env, jobject obj, jfieldID fieldID);
4. jshort (JNICALL *GetShortField)JNIEnv *env, jobject obj, jfieldID fieldID);
5. jlong (JNICALL *GetLongField)(JNIEnv *env, jobject obj, jfieldID fieldID);
6. jfloat (JNICALL *GetFloatField)(JNIEnv *env, jobject obj, jfieldID fieldID);
7. jdouble (JNICALL *GetDoubleField)(JNIEnv *env, jobject obj, jfieldID fieldID);
7、
函数原型:jfieldID (JNICALL *GetStaticFieldID)(JNIEnv *env, jclass clazz, const char *name, const char *sig);
函数说明:获取静态域ID
参数说明:同GetFieldID
返回类型:jfieldID
8、
函数原型:jbyte (JNICALL *GetStaticByteField)(JNIEnv *env, jclass clazz, jfieldID fieldID);
函数说明:获取静态域的数值
参数说明:jclass clazz FindClass函数获取到的Class,注意: 不是obj
fieldID fieldID 同GetIntField
返回类型:jbyte
9、
还有其它类型获取静态实例域的函数,使用方法同GetStaticByteField
1. jobject (JNICALL *GetStaticObjectField)(JNIEnv *env, jclass clazz, jfieldID fieldID); //jstring
2. jboolean (JNICALL *GetStaticBooleanField)(JNIEnv *env, jclass clazz, jfieldID fieldID);
3. jchar (JNICALL *GetStaticCharField)(JNIEnv *env, jclass clazz, jfieldID fieldID);
4. jshort (JNICALL *GetStaticShortField)(JNIEnv *env, jclass clazz, jfieldID fieldID);
5. jint (JNICALL *GetStaticIntField)(JNIEnv *env, jclass clazz, jfieldID fieldID);
6. jlong (JNICALL *GetStaticLongField)(JNIEnv *env, jclass clazz, jfieldID fieldID);
7. jfloat (JNICALL *GetStaticFloatField)(JNIEnv *env, jclass clazz, jfieldID fieldID);
8. jdouble (JNICALL *GetStaticDoubleField)(JNIEnv *env, jclass clazz, jfieldID fieldID);
10、
函数原型:void (JNICALL *SetObjectField)(JNIEnv *env, jobject obj, jfieldID fieldID, jobject val);
函数说明:设置fieldID对应获取的实例域的新值(非静态),此函数针对jstring
参数说明:jfieldID fieldID,有效的域ID
jobject val ,域的新值
返回类型:void
11、
函数原型:void (JNICALL *SetByteField)(JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val);
函数说明:设置字节型的实例域(非静态)
参数说明:同SetObjectField
返回类型:void
12、
还有其它类型的设置实例域的方法使用方法和SetByteField一样
1. void (JNICALL *SetBooleanField)(JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val);
2. void (JNICALL *SetCharField)(JNIEnv *env, jobject obj, jfieldID fieldID, jchar val);
3. void (JNICALL *SetShortField)(JNIEnv *env, jobject obj, jfieldID fieldID, jshort val);
4. void (JNICALL *SetIntField)(JNIEnv *env, jobject obj, jfieldID fieldID, jint val);
5. void (JNICALL *SetLongField)(JNIEnv *env, jobject obj, jfieldID fieldID, jlong val);
6. void (JNICALL *SetFloatField)(JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val);
7. void (JNICALL *SetDoubleField)(JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val);
13、
函数原型:void (JNICALL *SetStaticByteField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value);
函数说明:设置fieldID对应获取的实例域的新值(静态)
参数说明:jclass clazz,FindClass获取到的cla
返回类型:void
14、
还有其它类型的设置静态实例域的方法使用方法和SetStaticByteField一样
1. void (JNICALL *SetStaticObjectField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value);
2. void (JNICALL *SetStaticBooleanField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value);
3. void (JNICALL *SetStaticCharField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value);
4. void (JNICALL *SetStaticShortField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value);
5. void (JNICALL *SetStaticIntField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value);
6. void (JNICALL *SetStaticLongField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value);
7. void (JNICALL *SetStaticFloatField) (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value);
8. void (JNICALL *SetStaticDoubleField)(JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value);
以上方法使用的实例如下:
JNIEXPORT jstring JNICALL Java_com_lu_jni_TestCUtils_noPramaCallMethodReture
(JNIEnv * env , jobject objs){
jclass cls = (*env)->FindClass(env,"com/lu/jni/CommonUtil");
// //"()Ljava/lang/String;" 表示参数为空 返回值是String类型 ()V 无参 无返回
jmethodID method = (*env)->GetMethodID(env,cls,"callJavaRetureString","()Ljava/lang/String;");
jobject jobj = (*env)->AllocObject(env,cls);
jstring msg = (jstring)(*env)->CallObjectMethod(env,jobj,method);
const char * cjstring = "new String";
jstring jstr = (*env)->NewStringUTF(env,cjstring);
//找到对应类
jclass cls1 = (*env)->FindClass(env,"com/lu/jni/TestCUtils");
//创建实例
jobject obj = (*env)->AllocObject(env,cls1);
//获取实例域String
jfieldID mfieldid = (*env)->GetFieldID(env,cls1,"data","Ljava/lang/String;");
(*env)->SetObjectField(env,obj,mfieldid,jstr);
jstring getfieldValue = (jstring)(*env)->GetObjectField(env,obj,mfieldid);
const char *display = (*env)->GetStringUTFChars(env,getfieldValue,NULL);
LOGE("GET CLASS STRING FIELD VALUE == %s",display);
//获取实例域INT
mfieldid = (*env)->GetFieldID(env,cls1,"mInt","I");
jint getInt = (*env)->GetIntField(env,obj,mfieldid);
LOGE("GET CLASS INT FIELD VALUE == %d",getInt);
//获取byte实例域
jbyte mbyte = 45;
mfieldid = (*env)->GetFieldID(env,cls1,"mByte","B");
(*env)->SetByteField(env,obj,mfieldid,mbyte);
jbyte getByte = (*env)->GetByteField(env,obj,mfieldid);
LOGE("GET CLASS BYTE FIELD VALUE == %d",getByte);
//获取静态的byte实例域 必须使用findclass函数
mfieldid = (*env)->GetStaticFieldID(env,cls1,"staByte","B");
(*env)->SetStaticByteField(env,cls1,mfieldid,(jbyte)65);
jbyte getStaByte = (*env)->GetStaticByteField(env,cls1,mfieldid);
LOGE("GET CLASS STATIC BYTE FIELD VALUE == %d",getStaByte);
(*env)->ReleaseStringUTFChars(env,getfieldValue,display);
return msg;
}