创建java对象
NewObject:
使用NewObject可以用创建Java对象。
jobject NewObject(jclass clazz, jmethodID methodID, ...) {
va_list args;
jobject result;
va_start(args, methodID);
result = functions->NewObjectV(this,clazz,methodID,args);
va_end(args);
return result;
}
jobject NewObjectV(jclass clazz, jmethodID methodID,
va_list args) {
return functions->NewObjectV(this,clazz,methodID,args);
}
jobject NewObjectA(jclass clazz, jmethodID methodID,
const jvalue *args) {
return functions->NewObjectA(this,clazz,methodID,args);
}
构造方法:
GetMethodID能够取得构造方法的jmethodID。如果传入的要取得的方法名称设定为”<init>“就能够取得构造方法。
构造方法的返回值类类型的签名始终未Void。
示例:
java端:
public class TestMain {
public native void getjni();
public static void main(String[] args) {
// TODO Auto-generated method stub
System.loadLibrary("ConsoleApplication");
TestMain j = new TestMain();
j.getjni();
}
}
c++:
JNIEXPORT void JNICALL Java_com_cn_TestMain_getjni
(JNIEnv * env, jobject obj){
jclass cls_date=env->FindClass("java/util/Date");
jmethodID id_date=env->GetMethodID(cls_date,"<init>","()V");
jobject cur=env->NewObject(cls_date,id_date);
//long :J
jmethodID id_gettime=env->GetMethodID(cls_date,"getTime","()J");
jlong time=env->CallLongMethod(cur,id_gettime);
cout<<time<<endl;
};
结果:
AllocObject:
AllocObject可以根据传入的jclass创建一个Java对象,但是它的形态是非初始化的,在使用这个对象之前绝对要用CallNonVirtualVoidMethod来调用该jclass的构造函数,这样可以延迟构造函数的调用。这个用的很少。
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*)跟UTF-8编码的字符串(char*)。
const jchar *GetStringChars(jstring str, jboolean *isCopy) {
return functions->GetStringChars(this,str,isCopy);
}
const char* GetStringUTFChars(jstring str, jboolean *isCopy) {
return functions->GetStringUTFChars(this,str,isCopy);
}
第一个参数传入一个指向Java中的string对象的jstring变量。
第二个参数传入的是一个jboolean的指针。标示是否对Java的String对象进行复制的。如果传入的这个jboolean指针不是NULL,则会给该指针所指向的内存传入JNI_TRUE或JNI_FALSE标示是否进行了复制。传入NULL表示不关心是否复制字符串,它就不会给jboolean*指向的内存赋值。
这两个函数分别都会有两个不同的动作:
1.开新内容,然后把Java中的string复制到这个内存中,然后返回指向这个内存地址的指针。
2.直接返回指向Java中String的内存的指针,这个时候千万不要改变这个内存的内容,这将破坏String在Java中始终是常量这个原则。
使用这两个函数取得的字符串,在不适用的是偶,要使用ReleaseStringChars/ReleaseStringUTFChars来释放复制的内存或是释放地Java的String对象的引用。
void ReleaseStringChars(jstring str, const jchar *chars) {
functions->ReleaseStringChars(this,str,chars);
}
void ReleaseStringUTFChars(jstring str, const char* chars) {
functions->ReleaseStringUTFChars(this,str,chars);
}
第一个参数指定一个jstring变量,即是要释放的本地字符串的来源
第二个参数就是要释放的本地字符串
GetStringCritical
为了增加直接传回指向Java字符串的指针的可能性(而不是复制),JDK1.2出来了新的函数GetStringCritical/ReleaseStringCritical.
const jchar * GetStringCritical(jstring string, jboolean *isCopy) {
return functions->GetStringCritical(this,string,isCopy);
}
void ReleaseStringCritical(jstring string, const jchar *cstring) {
functions->ReleaseStringCritical(this,string,cstring);
}
在GetStringCritical/ReleaseStringCritical之间是一个关键区。在这个关键区之中绝对不要呼叫JNI的其他函数和会造成当前线程中断或是会让当前线程等待的本地代码,否则将造成关键区代码执行期间垃圾回收器停止运作,任何触发垃圾回收器的线程也会停止,其他的触发垃圾回收器的线程不能前进知道当前线程结束而激活垃圾回收器。
虽说这个函数会增加直接传回指向Java字符串的指针的可能性。不过还是会根据情况传回复制过的字符串。
不支持GetStringUTFCritical,没有这样的函数,由于Java字符串用的是UTF-16,要转成UTF-8编码的字符串始终需要进行一次复制。所以没有这样的函数。
GetStringRegion和GetStringUTFRegion
void (JNICALL *GetStringRegion)
(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
void (JNICALL *GetStringUTFRegion)
(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);
java 1.2出来的函数。这个函数的动作,是把Java字符串的内容直接复制到c/c++的字符数组中,在呼叫这个函数之前必须有一个c/c++分配出来的字符串,然后传入到这个函数中进行字符串的复制。
由于c/c++中分配内存开销相对小,而且Java中的String内容复制开销可以忽略,更好的一点是此函数不分配内存,不会抛出OutOfMemoryError异常。
其他的字符串函数:
jstring NewString(const jchar *unicode, jsize len) {
return functions->NewString(this,unicode,len);
}
jstring NewStringUTF(const char *utf) {
return functions->NewStringUTF(this,utf);
}
jsize GetStringLength(jstring str) {
return functions->GetStringLength(this,str);
}
jsize GetStringUTFLength(jstring str) {
return functions->GetStringUTFLength(this,str);
}
获取字符串属性并返回:
java端:
public class TestMain {
public String s="神马浮云";
public native void getjni();
public static void main(String[] args) {
// TODO Auto-generated method stub
System.loadLibrary("ConsoleApplication");
TestMain j = new TestMain();
j.getjni();
}
}
c/c++:
JNIEXPORT void JNICALL Java_com_cn_TestMain_getjni
(JNIEnv * env, jobject obj){
jclass cls=env->GetObjectClass(obj);
jfieldID fid=env->GetFieldID(cls,"s","Ljava/lang/String;");
jstring jstr=(jstring)env->GetObjectField(obj,fid);
const jchar* jchar=env->GetStringChars(jstr,NULL);
MessageBox(NULL,(const wchar_t*)(jchar),L"Title",MB_OK);
env->ReleaseStringChars(jstr,jchar);
};
输出的jchar*,而不是jstring。