JNI详解(一)

本文源码:http://download.csdn.net/detail/yongyu_it/9635971


1、什么是JNI

JNI是java语言的特性,它允许Java类的方法被C/C++实现。

2、JNIEnv指针

每个实现java原生方法的C/C++函数必须传入一个JNIEnv指针,C/C++通过JNIEnv提供的各种内置函数来使用JVM的功能。

注意:传入的JNIEnv指针只在对应java原生方法被调用的线程中有效,不可直接缓存,不可直接被其他线程使用!如需跨线程使用JNIEnv指针,需要将JNIEnv指针全局化。

3、对java引用数据类型的操作

引用数据类型的值不能被直接使用和修改

3.1 字符串操作

jstring和string互转

string jstringToString(JNIEnv * env, jstring str_src){
	//jboolean isCopy = true;
	jboolean isCopy = false;
	const char* str = env->GetStringUTFChars(str_src, &isCopy);
	string result = str;
	__android_log_print(ANDROID_LOG_INFO, COM_THINKING_J_DATA_TOOLS_LOG_TITLE, "jstring add is %x cstring add is %x", str, result.c_str());
	//通过env->GetStringUTFChars获取的字符串必须释放,否则会内存泄漏
	env->ReleaseStringUTFChars(str_src, str);
	return result;
}
或者

string jstringToString_2(JNIEnv* env, jstring str_src)
{
	char* c_str = NULL;
	jclass String_class = env->FindClass("java/lang/String");
	jstring str_code = env->NewStringUTF("utf-8");
	jmethodID getBytes_method = env->GetMethodID(String_class, "getBytes", "(Ljava/lang/String;)[B");
	jbyteArray j_byte_array = (jbyteArray)env->CallObjectMethod(str_src, getBytes_method, str_code);
	jsize j_byte_array_size = env->GetArrayLength(j_byte_array);
	jbyte* j_b = env->GetByteArrayElements(j_byte_array, 0);
	if (j_byte_array_size > 0)
	{
		c_str = (char*)malloc(j_byte_array_size + 1);
		memcpy(c_str, j_b, j_byte_array_size);
		c_str[j_byte_array_size] = 0;
	}
	env->ReleaseByteArrayElements(j_byte_array, j_b, 0);
	return c_str;
}

3.2 数组操作

下面展示的是两种返回数组操作结果的方法

JNIEXPORT jcharArray JNICALL Java_com_thinking_jdata_DataTest_do_1test_1array
(JNIEnv * env, jclass, jcharArray j_char_array){

	jsize j_char_array_size = env->GetArrayLength(j_char_array);
	jchar* j_c = env->GetCharArrayElements(j_char_array, 0);

	for (int i = 0; i < j_char_array_size; i++){
		__android_log_print(ANDROID_LOG_INFO, COM_THINKING_J_DATA_TOOLS_LOG_TITLE, "array index %i is %i from %x", i, *(j_c + i), (j_c + i));
		if (*(j_c + i) >= 97 && *(j_c + i) <= 122){
			*(j_c + i) -= 32;
		}
	}

	jcharArray result_array = env->NewCharArray(j_char_array_size);
	jchar * result = env->GetCharArrayElements(result_array, 0);
	if (j_char_array_size > 0){
		memcpy(result, j_c, j_char_array_size*sizeof(jchar));
	}

	env->ReleaseCharArrayElements(j_char_array, j_c, 0);
	env->ReleaseCharArrayElements(result_array, result, 0);
	return result_array;
}

3.3 NIO操作

对于java里面的直接缓冲区(Direct Buffer),jni可以直接获取直接缓冲区在内存上的地址并访问。基于此jni对缓冲区的更改将会保留(即java可以看得到更改)。


            // 约定:内存地址从小到大,小者为低位,大者为高位
            // java/C/C++ int都是4字节32位的
            // java的byte是1字节8位的,有符号,表示范围127~-128
            // C/C++的unsigned char是1字节8位的,无符号,表示范围0~255
            // java数值类型在计算机里面存储时,低位在前,高位在后
            // 例如:java int 1=0000 0000,0000 0000,0000 0000,0000 0001
            // 在计算机里面存储时,从低到高:0000 0001,0000 0000,0000 0000,0000 0000
            // 无论何种语言数组存储显然角标从小到大,在内存里面是由低到高存储的
            // 所以,java int 1当作byte[] 存储时,应该是:{0000 0001,0000 0000,0000 0000,0000 0000}
            // 而C/C++里面数值类型在计算机里存储时,高位在前,低位在后
            // 所以0000 0001,0000 0000,0000 0000,0000 0000= C/C++ int 16777216

            int size = 4;
            ByteBuffer b_buf = ByteBuffer.allocateDirect(size * 4);
            int[] data = new int[]{0, 1, 2, 3};
            b_buf.asIntBuffer().put(data, 0, size);
            DataTest.do_test_int_buffer(b_buf, size);
            int[] result = new int[size];
            b_buf.asIntBuffer().get(result, 0, size);
            b_buf.clear();

            Toast.makeText(this, result[0] + "," + result[1] + "," + result[2] + "," + result[3], Toast.LENGTH_LONG).show();
            result = null;



JNIEXPORT void JNICALL Java_com_thinking_jdata_DataTest_do_1test_1int_1buffer
(JNIEnv *env, jclass, jobject j_buffer, jint j_size){
	int* do_buffer = (int*)env->GetDirectBufferAddress(j_buffer);
	if (do_buffer == NULL) {
		__android_log_print(ANDROID_LOG_INFO, COM_THINKING_J_DATA_TOOLS_LOG_TITLE, "GetDirectBufferAddress Failed!");
		return;
	}
	for (int i = 0; i < j_size; i++){
		__android_log_print(ANDROID_LOG_INFO, COM_THINKING_J_DATA_TOOLS_LOG_TITLE, "pBuffer %i byte value is %i", i, do_buffer[i]);
		int int_value = jbytes_int(do_buffer + i) + 1;
		do_buffer[i] = jbytes_int(&int_value);
		__android_log_print(ANDROID_LOG_INFO, COM_THINKING_J_DATA_TOOLS_LOG_TITLE, "pBuffer %i int value is %i", i, do_buffer[i]);
	}
}
int jbytes_int(int * src_int){
	unsigned char * p_src = (unsigned char *)src_int;
	int size = sizeof(int) / sizeof(unsigned char);

	for (int i = 0; i < size; i++){
		__android_log_print(ANDROID_LOG_INFO, COM_THINKING_J_DATA_TOOLS_LOG_TITLE, "byte %i is %i", i, p_src[i]);
	}

	int* i_result = (int*)malloc(sizeof(int));
	unsigned char * p_result = (unsigned char *)i_result;
	for (int i = 0; i < 4; i++){
		p_result[i] = p_src[3 - i];
	}
	int result = *i_result;
	free(p_result);
	return result;
}








  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值