JNI学习笔记——创建JAVA对象和内部类需注意

跨过了基本类型和基本类型数组的坑后,迈入对象和对象型数据(包括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(构造函数函数名为,第三个参数为签名,意指传参和返回的对应缩写)
	jmethodID jmi = env->GetMethodID(jc,"","()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

找到原因,修改后的代码:

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(构造函数函数名为,第三个参数为签名,意指传参和返回的对应缩写)
	jmethodID jmi = env->GetMethodID(jc,"","(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,"","()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;
}
至此完整,对象调用的易错点攻破,开始进发下一步



你可能感兴趣的:(JNI学习笔记——创建JAVA对象和内部类需注意)