本文源码: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;
}