在c/c++本地代码中创建Java对象
1,使用函数NewObject可以用来创建JAVA对象;
GetMethodID 能够取得构造方法的jmethodID, 如果传入的要取得的方法名称设为"<init>"就能够取得构造方法
构造方法的方法返回值类型的签名始终为void
例:
jclass clazz_date = env->FindClass("java/util/Date");
jmethodID mid_date = env->GetMethoID(clazz_date, "<init>", "()V");
jobject now = env->NewObject(clazz_date, mid_date);
jmethodID mid _date_getTime = env->GetMethodID(clazz_date, "getTime" , "()")
jlong time = env->CallLongMethod(now, mid_date_getTime);
2,使用函数AllocObject来创建JAVA对象
使用函数AllocObject可以根据传入的jclass创建一个JAVA对象,便是他的状态是非初始化的,在使用这个对象之前绝对要用CallNovirtualVoidMethod来调用该jclass的建构函数,这样可以延迟构造函数的调用,这一个部分用的很少,在这里只做简单的说明。
jclass clazz_str = env->FindClass("java/lang/String");
jmethodID methodID_str = env->GetMethodID(clazz_str ,"<init>", "([C)V");
//预先创建一个没有初始化的字符串
jobject string = env->AllocObject(clazz_str);
//创建一个4个元素的的字符数组,然后以“清”,“原”,“卓”,“也”赋值
jcharArra arg = env->NewCharArray(4);
env->SetCharArrayRegion(arg, 0, 4,L"清原卓也");
// 呼叫构建子
env->CallNovirtualVoidMethod(string ,clazz_str,methodID,arg);
jclass clazz_this = env->GetObjectClass(obj);
//这里假设这个对象的类有定义
static string STATIC_STR;
jfieldID fieldID_str = env->GetStaticFieldID(clazz_this,"STATIC_STR","Ljava/lang/String");
env->SetStaticObjectField(clazz_str, fieldID_str, string);
- JAVA字串 <----->c/c++的字串
在JAVA中,使用的字符串String对象是Unicode(UTF-16)码,即每个字符不论是中文还是英文还是符号,一个字符总是占两个字节
JAVA通过JNI接口可以将JAVA的字符串转换到C/C++中的宽字符串(wchar_t*),或是传回一个
UTF-8的字符串(char *)到C/C++,反过来,C/C++可以通过一个宽字符串,或是一个UTF-8编码的字符串来创建一个JAVA端的String对象
GetStringChars
GetStringUTFChars
这两个函数用来取得与某个jstring对象相关的JAVA字符串,分别可以取得UTF-16编码的宽字符串(jchar*)跟UTF8编码的字符串(char*)
cost jchar* GetStringChars(jstring str, jboolean* copied)
cost char* GetStringUTFChars(jstring str, jboolean *copied)
第一个参数传入一个指向JAVA的String对象的jstring变量
第二个参数传入的是一个jboolean的指针
这两个函数分别都会有两个不同的动作:
1,开辟新的内存,然后把JAVA中的String拷贝到这个内存中,然后返回指向这个内存地址的指针。
2,直接返回指向JAVA的String的内存的指针,这个时候千万不要改变这个内存的内容,这将破坏String在Java中始终是常量这个原则
第二个参数是用来标示是否对Java的String对象进行了拷贝的。
如果传入的这个jboolean指针不是NULL,则他会给该指针所指向的内存传入JNI_TRUE 或 JNI _FALSE标示是否进行了拷贝。
传入NULL表示不关心是否拷贝字符串,它就不会给jboolean*指向的内存赋值
使用这两个函数取得的字符串,在不使用的时候,要使用ReleaseStringChars/ReleaseStringUTFChars来释放拷贝的内存,或是释放对JAVA的String对象的引用。
ReleaseStringChars(jstring jstr, const jchar* str)
ReleaseStringUTFChars(jstring jstr, const char* str)
第一个参数指定一个jstring 变量,即是要释放的本地字符串的来源
第二个参数就是要释放的本地字符串
GetStringCritical
为了增加直接传回指向JAVA字符串的指针的可能性(而不是拷贝),JDK1.2出来了新的函数GetStringCritical/ReleaseStringCritical
const jchar* GetStringCritical(jstring str, jboolean* copied);
void ReleaseStringCritical(jstring jstr, const jchar* str);
在GetStringCritical/ReleaseStringCritical之间是一个关键区,在这关键区之中绝对不能呼叫JNI的其它函数和会造成当前线程中断或是会让当前线程等待的任何本地代码,否则将造成关键区代码执行期间垃圾回收器停止动作,任何触发垃圾回收器的线程也会暂停,其他的触发垃圾回收器的线程不能前进直到当前线程结束而激活垃圾回收器
在关键区千万不要出现中断操作,或是在JVM中分配任何新对象,否则会造成JVM死锁。
虽说这个函数会增加直接传回指向JAVA字符串的指针的可能性,不过还是会根据情况传回拷贝过的字符串
不支持GetStringUTFCritical,没有这样的函数,因为JAVA字符串用的是UTF-16,要转换成UTF-8编码的字符串始终需要进行一次拷贝,所以没有这样的函数
GetStringRegion
GetStringUTFRegion
JAVA1.2F出来的函数,这个函数的动作,是把JAVA字符串的内容直接拷贝到C/C++的字符数组中,在呼叫这个函数之前必须有一个C/C++分配出来的字符串,然后传入到这个函数中进行字符串的拷贝。
由于C/C++分配内存开销相对小,而且JAVA中的String内容拷贝的开销可以忽略,更好的一点是些函数不会分配内存,不会抛出OutOfMemoryError异常
//拷贝JAVA字符串并以UTF-8编码传入buffer
GetStringUTFRegion(jstring str , jsize start, jsize len, char* buffer);
//拷贝JAVA字符串并以UTF-16编码传入buffer
GetStringRegion(jstring str , jsize start, jsize len, char* buffer);
其他的字符串函数
jstring NewString(const jchar* str , jsize len);
jstring NewStringUTF(const char* str);
jsize GetStringLength(jstring str);
jsize GetStringUTFLength(jstring str)