在这篇文章里记录一下C语言操作java数组的相关方法,通过一个简单的程序实现:在c语言里使用java生成的数组,在java里使用c语言生成的数组。
首先我们来看一下,c语言和java语言里数据类型是如何对应的
// 基本类型
typedef unsigned char jboolean; /* unsigned 8 bits */
typedef signed char jbyte; /* signed 8 bits */
typedef unsigned short jchar; /* unsigned 16 bits */
typedef short jshort; /* signed 16 bits */
typedef int jint; /* signed 32 bits */
typedef long long jlong; /* signed 64 bits */
typedef float jfloat; /* 32-bit IEEE 754 */
typedef double jdouble; /* 64-bit IEEE 754 */
typedef jint jsize;
// 对象类型
typedef void* jobject;
typedef jobject jclass;
typedef jobject jstring;
typedef jobject jarray;
typedef jarray jobjectArray;
typedef jarray jbooleanArray;
typedef jarray jbyteArray;
typedef jarray jcharArray;
typedef jarray jshortArray;
typedef jarray jintArray;
typedef jarray jlongArray;
typedef jarray jfloatArray;
typedef jarray jdoubleArray;
typedef jobject jthrowable;
typedef jobject jweak;
这里只截取与C语言有关的部分,如果想查看全部对应关系,请参考${ndk_dir}/platforms/android-14/arch-arm/usr/include/jni.h
jobjectArray (*NewObjectArray)(JNIEnv*, jsize, jclass, jobject);
// 参数第四个参数用来初始化数组(All elements are initially set to initialElement.)
jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize);
jbyteArray (*NewByteArray)(JNIEnv*, jsize);
jcharArray (*NewCharArray)(JNIEnv*, jsize);
jshortArray (*NewShortArray)(JNIEnv*, jsize);
jintArray (*NewIntArray)(JNIEnv*, jsize);
jlongArray (*NewLongArray)(JNIEnv*, jsize);
jfloatArray (*NewFloatArray)(JNIEnv*, jsize);
jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize);
jsize (*GetArrayLength)(JNIEnv*, jarray);
jobject (*GetObjectArrayElement)(JNIEnv*, jobjectArray, jsize);
// 最后一个参数是要获取的对象在数组里的下标
jboolean* (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*);
jbyte* (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*);
jchar* (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*);
jshort* (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*);
jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
jlong* (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*);
jfloat* (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*);
jdouble* (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*);
A family of functions that returns the body of the primitive array. The result is valid until the corresponding ReleaseArrayElements() function is called. Since the returned array may be a copy of the Java array, changes made to the returned array will not necessarily be reflected in the original array until ReleaseArrayElements() is called.
If isCopy is not NULL, then *isCopy is set to JNI_TRUE if a copy is made; or it is set to JNI_FALSE if no copy is made.
PS:第三个参数:JNI_TRUE或者JNI_FALSE或者0
PS:如果我们调用这些方法时没有把数组赋值一份,用完后也需要调用对应的ReleaseArrayElements方法释放资源,否则会内存泄漏。
void (*SetObjectArrayElement)(JNIEnv*, jobjectArray, jsize, jobject);
void (*ReleaseBooleanArrayElements)(JNIEnv*, jbooleanArray,
jboolean*, jint);
void (*ReleaseByteArrayElements)(JNIEnv*, jbyteArray,
jbyte*, jint);
void (*ReleaseCharArrayElements)(JNIEnv*, jcharArray,
jchar*, jint);
void (*ReleaseShortArrayElements)(JNIEnv*, jshortArray,
jshort*, jint);
void (*ReleaseIntArrayElements)(JNIEnv*, jintArray,
jint*, jint);
void (*ReleaseLongArrayElements)(JNIEnv*, jlongArray,
jlong*, jint);
void (*ReleaseFloatArrayElements)(JNIEnv*, jfloatArray,
jfloat*, jint);
void (*ReleaseDoubleArrayElements)(JNIEnv*, jdoubleArray,
jdouble*, jint);
最后一个参数:
0——-copy back the content and free the elems buffer
JNI_COMMIT——-copy back the content but do not free the elems buffer
JNI_ABORT——-free the buffer without copying back the possible changes
如果有其他参数不明白什么意思,可以参考http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/functions.html#wp9502
–
public class MainActivity extends Activity {
public native int[] testArray(byte[] array);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
#include "net_qingtian_array_MainActivity.h"
#include <android/log.h>
JNIEXPORT jintArray JNICALL Java_net_qingtian_array_MainActivity_testArray
(JNIEnv * env, jobject obj, jbyteArray _jbyteArray)
{
// 获取数组长度
jsize length = (*env)->GetArrayLength(env, _jbyteArray);
__android_log_print(ANDROID_LOG_INFO, "qingtian", "byte数组长度:%d", length);
// 获取c语言的数组
jbyte* _bytes = (*env)->GetByteArrayElements(env, _jbyteArray, JNI_FALSE);
// 打印数组
int i = 0;
for(i = 0 ; i < length ; i ++){
__android_log_print(ANDROID_LOG_INFO, "qingtian", "byte数组第%d个值:%d", i, _bytes[i]);
}
// 释放byte数组资源
(*env)->ReleaseByteArrayElements(env, _jbyteArray, _bytes, 0);
// 生成jint数组,长度为传递进来的数组的两倍
jsize newLength = length * 2;
jintArray _jintArray = (*env)->NewIntArray(env, newLength);
// 获取jintArray对应的本地数组
jint* _jints = (*env)->GetIntArrayElements(env, _jintArray, JNI_FALSE);
// 赋值
for(i = 0 ; i < newLength ; i ++){
_jints[i] = 20 + i;
}
// 释放int数组资源
(*env)->ReleaseIntArrayElements(env, _jintArray, _jints, 0);
// 返回int数组
return _jintArray;
}
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 对应打包成函数库的名字
LOCAL_MODULE := array
# 对应c代码的文件
LOCAL_SRC_FILES := array.c
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
public class MainActivity extends Activity {
static {
System.loadLibrary("array");
}
public native int[] testArray(byte[] array);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
byte[] bytes = new byte[]{0, 1, 2};
int[] ints = testArray(bytes);
Log.d("qingtian", "int数组的长度是:"+ints.length);
for(int i = 0 ; i < ints.length ; i ++){
Log.d("qingtian", String.format("int数组第%d个值:%d", i, ints[i]));
}
}
}
–
祝大家元旦快乐。