jni字符串乱码,异常,引用....

//访问构造方法
//使用java.util.Date产生一个当前的时间戳
JNIEXPORT jobject JNICALL Java_com_dongnaoedu_jni_JniTest_accessConstructor
(JNIEnv *env, jobject jobj){
	jclass cls = (*env)->FindClass(env, "java/util/Date");
	//jmethodID
	jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "<init>", "()V");
	//实例化一个Date对象
	jobject date_obj = (*env)->NewObject(env, cls, constructor_mid);
	//调用getTime方法
	jmethodID mid = (*env)->GetMethodID(env, cls, "getTime", "()J");
	jlong time = (*env)->CallLongMethod(env, date_obj, mid);

	printf("\ntime:%lld\n",time);

	return date_obj;
}

//调用父类的方法
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_accessNonvirtualMethod
(JNIEnv *env, jobject jobj){
	jclass cls = (*env)->GetObjectClass(env, jobj);
	//获取man属性(对象)
	jfieldID fid = (*env)->GetFieldID(env, cls, "human", "Lcom/dongnaoedu/jni/Human;");
	//获取
	jobject human_obj = (*env)->GetObjectField(env, jobj, fid);

	//执行sayHi方法
	jclass human_cls = (*env)->FindClass(env, "com/dongnaoedu/jni/Human"); //注意:传父类的名称
	jmethodID mid = (*env)->GetMethodID(env, human_cls, "sayHi", "()V");

	//执行
	//(*env)->CallObjectMethod(env, human_obj, mid);
	//调用的父类的方法
	(*env)->CallNonvirtualObjectMethod(env, human_obj, human_cls, mid);
}

//中文问题
JNIEXPORT jstring JNICALL Java_com_dongnaoedu_jni_JniTest_chineseChars
(JNIEnv *env, jobject jobj, jstring in){
	//输出
	//char *c_str = (*env)->GetStringUTFChars(env, in, JNI_FALSE);
	//printf("%s\n",c_str);

	//c -> jstring
	char *c_str = "马蓉与宋江";
	//char c_str[] = "马蓉与宋喆";
	//jstring jstr = (*env)->NewStringUTF(env, c_str);
	//执行String(byte bytes[], String charsetName)构造方法需要的条件
	//1.jmethodID
	//2.byte数组
	//3.字符编码jstring

	jclass str_cls = (*env)->FindClass(env, "java/lang/String");
	jmethodID constructor_mid = (*env)->GetMethodID(env, str_cls, "<init>", "([BLjava/lang/String;)V");

	//jbyte -> char 
	//jbyteArray -> char[]
	jbyteArray bytes = (*env)->NewByteArray(env, strlen(c_str));
	//byte数组赋值
	//0->strlen(c_str),从头到尾
	//对等于,从c_str这个字符数组,复制到bytes这个字符数组
	(*env)->SetByteArrayRegion(env, bytes, 0, strlen(c_str), c_str);

	//字符编码jstring
	jstring charsetName = (*env)->NewStringUTF(env, "GB2312");

	//调用构造函数,返回编码之后的jstring
	return (*env)->NewObject(env,str_cls,constructor_mid,bytes,charsetName);
}

int compare(int *a,int *b){
	return (*a) - (*b);
}

//传入
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_giveArray
(JNIEnv *env, jobject jobj, jintArray arr){
	//jintArray -> jint指针 -> c int 数组
	jint *elems = (*env)->GetIntArrayElements(env, arr, NULL);
	//printf("%#x,%#x\n", &elems, &arr);

	//数组的长度
	int len = (*env)->GetArrayLength(env, arr);
	//排序
	qsort(elems, len, sizeof(jint), compare);	

	//同步
	//mode
	//0, Java数组进行更新,并且释放C/C++数组
	//JNI_ABORT, Java数组不进行更新,但是释放C/C++数组
	//JNI_COMMIT,Java数组进行更新,不释放C/C++数组(函数执行完,数组还是会释放)
	(*env)->ReleaseIntArrayElements(env, arr, elems, JNI_COMMIT);
}

//返回数组
JNIEXPORT jintArray JNICALL Java_com_dongnaoedu_jni_JniTest_getArray(JNIEnv *env, jobject jobj, jint len){
	//创建一个指定大小的数组
	jintArray jint_arr = (*env)->NewIntArray(env, len);
	jint *elems = (*env)->GetIntArrayElements(env, jint_arr, NULL);	
	int i = 0;
	for (; i < len; i++){
		elems[i] = i;
	}

	//同步
	(*env)->ReleaseIntArrayElements(env, jint_arr, elems, 0);	

	return jint_arr;
}


//JNI 引用变量
//引用类型:局部引用和全局引用
//作用:在JNI中告知虚拟机何时回收一个JNI变量

//局部引用,通过DeleteLocalRef手动释放对象
//1.访问一个很大的java对象,使用完之后,还要进行复杂的耗时操作
//2.创建了大量的局部引用,占用了太多的内存,而且这些局部引用跟后面的操作没有关联性

//模拟:循环创建数组
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_localRef(JNIEnv *env, jobject jobj){
	int i = 0;
	for (; i < 5; i++){
		//创建Date对象
		jclass cls = (*env)->FindClass(env, "java/util/Date");
		jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "<init>", "()V");
		jobject obj = (*env)->NewObject(env, cls, constructor_mid);
		//此处省略一百行代码...

		//不在使用jobject对象了
		//通知垃圾回收器回收这些对象
		(*env)->DeleteLocalRef(env, obj);
		//此处省略一百行代码...
	}
}


//全局引用
//共享(可以跨多个线程),手动控制内存使用
jstring global_str;

//创建
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_createGlobalRef(JNIEnv *env, jobject jobj){
	jstring obj = (*env)->NewStringUTF(env, "jni development is powerful!");
	global_str = (*env)->NewGlobalRef(env, obj);
}

//获得
JNIEXPORT jstring JNICALL Java_com_dongnaoedu_jni_JniTest_getGlobalRef(JNIEnv *env, jobject jobj){
	return global_str;
}

//释放
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_deleteGlobalRef(JNIEnv *env, jobject jobj){
	(*env)->DeleteGlobalRef(env, global_str);
}

//弱全局引用
//节省内存,在内存不足时可以是释放所引用的对象
//可以引用一个不常用的对象,如果为NULL,临时创建
//创建:NewWeakGlobalRef,销毁:DeleteGlobalWeakRef

//异常处理
//1.保证Java代码可以运行
//2.补救措施保证C代码继续运行

//JNI自己抛出的Throwable异常,在Java层被相应异常catch捕捉,还能在C层清空
//用户通过ThrowNew抛出的异常,可以在Java层捕捉
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_exeception(JNIEnv *env, jobject jobj){
	jclass cls = (*env)->GetObjectClass(env, jobj);
	jfieldID fid = (*env)->GetFieldID(env, cls, "key2", "Ljava/lang/String;");
	//检测是否发生Java异常
	jthrowable exception = (*env)->ExceptionOccurred(env);
	if (exception != NULL){
		//让Java代码可以继续运行
		//清空异常信息
		(*env)->ExceptionClear(env);

		//补救措施
		fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");
	}

	//获取属性的值
	jstring jstr = (*env)->GetObjectField(env, jobj, fid);
	char *str = (*env)->GetStringUTFChars(env, jstr, NULL);

	//对比属性值是否合法
	if (_stricmp(str, "super jason") != 0){
		//认为抛出异常,给Java层处理
		jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
		(*env)->ThrowNew(env,newExcCls,"key's value is invalid!");
	}
}

//缓存策略

//static jfieldID key_id 
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_cached(JNIEnv *env, jobject jobj){
	jclass cls = (*env)->GetObjectClass(env, jobj);	
	//获取jfieldID只获取一次
	//局部静态变量
	static jfieldID key_id = NULL;
	if (key_id == NULL){
		key_id = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");
		printf("--------GetFieldID-------\n");
	}
}

//初始化全局变量,动态库加载完成之后,立刻缓存起来
jfieldID key_fid;
jmethodID random_mid;
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_initIds(JNIEnv *env, jclass jcls){	
	key_fid = (*env)->GetFieldID(env, jcls, "key", "Ljava/lang/String;");
	random_mid = (*env)->GetMethodID(env, jcls, "genRandomInt", "(I)I");
}

访问构造方法和访问普通方法的一个区别是其中的一个参数是<init>,从jni层向java层返回中文字符串会出现乱码,所以要改变编码为GB2312,要改变java层的字符串,需要在jni层改变厚同步才能在java层收到变化。java层native代码

public class JniTest {

	public String key = "jason";
	
	public Human human = new Man(); 
	
	public static int count = 9;
	
	public native static String getStringFromC();
	
	public native String getString2FromC(int i);
	//访问属性,返回修改之后的属性内容
	public native String accessField();
	
	public native void accessStaticField();
	
	public native void accessMethod();
	
	public native void accessStaticMethod();
	
	public native Date accessConstructor();
	
	public native void accessNonvirtualMethod();
	
	public native String chineseChars(String in);
	
	public native void giveArray(int[] array);
	
	public native int[] getArray(int len);
	
	public native void localRef();
	
	public native void createGlobalRef();
	
	public native String getGlobalRef();
	
	public native void deleteGlobalRef();
	
	public native void exeception();
	
	public native void cached();
	
	public native static void initIds();
	
	public static void main(String[] args) {
		String text = getStringFromC();
		System.out.println(text);
		JniTest t = new JniTest();
		text = t.getString2FromC(6);
		System.out.println(text);
		
		System.out.println("key修改前:"+t.key);
		t.accessField();
		System.out.println("key修改后:"+t.key);
		
		System.out.println("count修改前:"+count);
		t.accessStaticField();
		System.out.println("count修改后:"+count);
		
		t.accessMethod();
		t.accessStaticMethod();
		
		t.accessConstructor();
		
		t.accessNonvirtualMethod();
		
		System.out.println(t.chineseChars("宋喆"));
		
		int[] array = {9,100,10,37,5,10};
		//排序
		t.giveArray(array);
		for (int i : array) {
			System.out.println(i);
		}
		
		//----------
		int[] array2 = t.getArray(10);
		System.out.println("------------");
		for (int i : array2) {
			System.out.println(i);
		}
		
		System.out.println("------08-17------");
		t.createGlobalRef();
		System.out.println(t.getGlobalRef());
		//用完之后释放
		t.deleteGlobalRef();
		System.out.println("释放完了...");
		//System.out.println(t.getGlobalRef());
		
		try {
			t.exeception();						
		} catch (Exception e) {
			System.out.println("发生异常:"+e.getMessage());
		}
		
		System.out.println("--------异常发生之后-------");
		
		try {
			t.exeception();
		} catch (Exception e) {
			//e.printStackTrace();
			System.out.println(e.getMessage());
		}
		
		//不断调用cached方法
		for (int i = 0; i < 100; i++) {
			t.cached();
		}
	}
	
	//产生指定范围的随机数
	public int genRandomInt(int max){
		System.out.println("genRandomInt 执行了...");
		return new Random().nextInt(max); 
	}
	
	//产生UUID字符串
	public static String getUUID(){
		return UUID.randomUUID().toString();
	}
	
	//加载动态库
	static{	
		System.loadLibrary("jni_study");
		initIds();
	}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值