跨过了基本类型和基本类型数组的坑后,迈入对象和对象型数据(包括String)
String类的基本操作从传入到传出网上例子数不胜数,关键在于资源的释放和回收,以及容错处理
jobjectArray Java_com_smile_jnitest_JNITest_sort
(JNIEnv *env, jclass, jobjectArray strs){
int size = env->GetArrayLength(strs);
const char* ns[size];
jclass jc = env->FindClass("java/lang/String");
jobjectArray result = env->NewObjectArray(size,jc,0);
for (int i = 0; i < size; ++i) {
jobject job = env->GetObjectArrayElement(strs,i);
jstring str = (jstring)job;
int size = env->GetStringUTFLength(str);
const char* cs = env->GetStringUTFChars(str,NULL);
/* 这里曾先用数组接收值,下个循环再循环接收的数组,给返回值数组赋值
* ns[i] = cs;
* 很遗憾失败了,返回的字符串数组丢值了,很明显没保存下来,待研究
*/
jstring js = env->NewStringUTF(cs);
env->SetObjectArrayElement(result,i,js);
env->ReleaseStringUTFChars(str,cs);
}
return result;
}
磕磕碰碰的也算完成了测试,不过编码问题和类型转换问题还待深入
完成了String这个简单对象,开始往复杂的自定义对象进发。
很遗憾我一开始就选择了一个不明智的开局:自定义内部类
第一次的代码:
jobject Java_com_smile_jnitest_JNITest_testObj
(JNIEnv *env, jclass c, jint x, jstring y){
//查找class镜像
jclass jc = env->FindClass("com/smile/jnitest/JNITest$TestPoint");
//获取构造函数ID(构造函数函数名为<init>,第三个参数为签名,意指传参和返回的对应缩写)
jmethodID jmi = env->GetMethodID(jc,"<init>","()V");
jmethodID jmiSetX = env->GetMethodID(jc,"setX","(I)V");
jfieldID jfiY = env->GetFieldID(jc,"y","Ljava/lang/String");
jmethodID jmiGetY = env->GetMethodID(jc,"getY","()Ljava/lang/String");
jobject testPoint = env->NewObject(jc,jmi);
env->CallVoidMethod(testPoint,jmiSetX,x);
env->SetObjectField(testPoint,jfiY,y);
jstring getString = (jstring)env->CallObjectMethod(testPoint,jmiGetY);
const char* preStr = env->GetStringUTFChars(getString,NULL);
char* endStr = "cao";
char *newStr = NULL;
int nLen = strlen(preStr) + strlen(endStr);
newStr = new char[nLen+1];
memset(newStr,0,nLen+1);
strcat(newStr,preStr);
strcat(newStr,endStr);
//制定编码格式为UTF8
newStr[nLen] = '\0';
jstring newJstr = env->NewStringUTF(newStr);
env->SetObjectField(testPoint,jfiY,newJstr);
env->ReleaseStringUTFChars(getString,preStr);
return testPoint;
}
以上代码跑起来肯定死机,妥妥的,因为犯了两个错误。
1:参数签名--Signature 中指定非基本类型的类对象签名格式为 L+类的全名(包括包名)+;,有眼无珠的我漏掉了“;”,因为我没看到它。
2:JAVA中创建内部类对象如何创建?内部类依托外部的主类生存,可以理解为无父就无子,创建内部类,先要创建其外部主类。
于是其构造函数就必须传入其外部主类,使用 javap -s 命令也可查询到,该内部类的构造签名为 Signature: (L外部主类;)V
找到原因,修改后的代码:
<span style="font-size:10px;">jobject Java_com_smile_jnitest_JNITest_testObj
(JNIEnv *env, jclass c, jint x, jstring y){
//查找class镜像
jclass jc = env->FindClass("com/smile/jnitest/JNITest$TestPoint");
//获取构造函数ID(构造函数函数名为<init>,第三个参数为签名,意指传参和返回的对应缩写)
jmethodID jmi = env->GetMethodID(jc,"<init>","(Lcom/smile/jnitest/JNITest;)V");
jmethodID jmiSetX = env->GetMethodID(jc,"setX","(I)V");
jfieldID jfiY = env->GetFieldID(jc,"y","Ljava/lang/String;");
jmethodID jmiGetY = env->GetMethodID(jc,"getY","()Ljava/lang/String;");
//获取外部类构造函数
jmethodID pjmi = env->GetMethodID(c,"<init>","()V");
//创建外部类实例
jobject pointParent = env->NewObject(c,pjmi);
//根据外部类实例创建内部类
jobject testPoint = env->NewObject(jc,jmi,pointParent);
env->CallVoidMethod(testPoint,jmiSetX,x);
env->SetObjectField(testPoint,jfiY,y);
jstring getString = (jstring)env->CallObjectMethod(testPoint,jmiGetY);
const char* preStr = env->GetStringUTFChars(getString,NULL);
char* endStr = "cao";
char *newStr = NULL;
int nLen = strlen(preStr) + strlen(endStr);
newStr = new char[nLen+1];
memset(newStr,0,nLen+1);
strcat(newStr,preStr);
strcat(newStr,endStr);
//制定编码格式为UTF8
newStr[nLen] = '\0';
jstring newJstr = env->NewStringUTF(newStr);
env->SetObjectField(testPoint,jfiY,newJstr);
env->ReleaseStringUTFChars(getString,preStr);
return testPoint;
}</span>
至此完整,对象调用的易错点攻破,开始进发下一步