1. 在 C /C++ 本地代码中创立 Java 的对象
1.1 Java 对象的创立应用 NewObject 办法
- 应用函数 NewObject 能够用来创立 Java 对象
- GetMethod 可能获得构造方法的 jmethodID,如果传入的要取的办法名称设定为 “<init>” 就可能获得构造方法
- 因为构造方法没有返回值,所以构造方法的办法返回值类型的签名始终为 void
案例
jclass class_date = env->FindClass("java/util/Date");
jmethodID mid_date = env->GetMethodId(class_date, "<init>", "()V");
jobject now = env->NewObject(class_date, mid_date);
jmethodID mid_date_getTime = env->GetMethod(class_date , "getTime", "()j");
jlong time = CallLongMethod(now, mid_date_getTime);
cout << time << endl;
1.2 Java 对象的创立 AllocObject
- 应用函数 AllocObject 能够依据传入的 jclass 创立一个 Java 对象,然而他的状态是非初始化的,在应用这个对象之前肯定要调用 CallNonvirtualVoidMethod 来调用该 jclass 的构造函数,这样就能够提早构造函数的调用。这一个局部用的很少,在这里只做简略的阐明。
jclass clazz_str = env->FindClass("java/lang.String");
jmethodID methodID_str = env->GetMethodID(clazz_str, "<init>", "([C)V");
// 事后创立一个没有初始化的字符串
jobject str = env->AllocObject(clazz_str);
// 创立一个 4 个元素的字符串数组,而后以 'B' 'U' 'G' '弄' '潮' '儿' 赋值
jcharArray arg = env->NewCharArray(6);
env->SetCharArrayRegion(arg, 0, 6, L"BUG 弄潮儿");
// 调用构造函数
env->CallNonvirtualVoidMethod(str, clazz_str, methodID_str, arg);
jclass clazz_this = env->GetObjectClass(obj);
// 这里假如这个对象的类中有定义 static String STATIC_STR;
jfieldID jfield_str = env->GetStaticField(clazz_this, "STATIC_STR", "Ljava/lang/String;");
env->SetStaticObjectField(clazz_str, jfield_str, str);
2. Java 字符串 & C/C++ 的字符串
在 C /C++ 本地代码中拜访 Java 的 String 字符串对象
在 C /C++ 本地代码中创立 Java 的 String 字符串对象
- 在 Java 中,应用的字符串 String 对象是 Unicode (UTF-16) 编码,即每个字符不论是中文、英文还是符号,一个字符总是占两个字节
- Java 通过 JNI 接口能够将 Java 的字符串转换到 C/C++ 中的宽字符串(wchar_t*),或者是传回一个 UTF- 8 的字符串(char*)到 C/C++。反过来,C/C++ 能够通过一个宽字符串,或者是一个 UTF-8 编码的字符串来创立一个 Java 端的 String 对象
2.1 GetStringChars & GetStringUTFChars
GetStringChars
GetStringUTFChars
- 这两个函数用来获得某个 jstring 对象相干的 Java 字符串。别离能够获得 UTF-16 编码的宽字符串(jchar*)与 UTF8 编码的字符串(char*)
const jchar* GetStringChars(jstring str, jboolean* copied);
const char* GetStringUTFChars(jstring str, jboolean* copied);
第一个参数传入一个指向 Java 中的 String 字符串对象的 jstring 变量;
第二参数传入的是一个 jboolean 的指针;
- 这两个函数别离都会有两个不同的动作:
- 开拓新内存,而后把 Java 中的 String 拷贝到这个内存中,而后返回指向这个内存地址的指针
- 间接返回指向 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 变量,即是要开释的本地字符串的起源;
第二个参数就是要开释的本地字符串;
2.2 GetStringCritical
- 为了减少间接传入指向 Java 字符串的指针的可能性(而不是拷贝),JDK 1.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 字符串用的是 UTF16 编码,要转换成 UTF8 编码的字符串始终须要进行一次拷贝,所以没有这样的函数。
2.3 GetStringRegin & GetStringUTFRegion
- Java 1.2 减少了 GetStringRegin / GetStringUTFRegion 函数。这个函数的动作,是把 Java 字符串的内容间接拷贝到 C/C++ 的字符数组中。在调用这个函数之前必须有一个 C/C++ 调配进去的字符串,而后传入到这个函数中进行字符串的拷贝
- 因为 C/C++ 中分配内存开销绝对小,而且 Java 中的 String 内容拷贝的开销能够疏忽,更好的一点是此函数不分配内存,不会抛出 OutOfMemoryError 异样
// 拷贝 Java 字符串并以 UTF- 8 编码传入 buffer
GetStringUTFRegion(jstring srt, jsize start, jsize len, char* buffer);
// 拷贝 Java 字符串并以 UTF-16 编码传入 buffer
GetStringRegion(jstring srt, jsize start, jsize len, char* buffer);
2.4 其余字符串函数
jstring NewString(const jchar* str, jsize len);
jstring NewStringUTF(const char* str);
jsize GetStringLength(jstring str);
jsize GetStringUTFLength(jstring str);