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; }
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: 深入理解JNI
- 下一篇: Java中JNI的使用详解第一篇:HelloWorld