在Android NDK探究奥秘二中已经列出了一个Java类型到本地映射关系 的表格。那么从C类型转化到映射的本地Java类型是怎么转化的呢?本章将给出详细答案。
基本类型转化
Java的基本类型映射到本地类型是jboolean、jbyte、jchar、jshort、jint 、jlong、jfloat、jdouble。那么我们先看看jni.h中是怎么定义的。
其中 jshort 、jint、jlong、jfloat、jdouble都是C中定义相似的。用的时候直接可以当作C中的去掉j的基本类型。jboolean、jbyte,要在C中的char类型来定义,jchar是C中的short类型定义。那么在Java基本类型映射的本地类型中和C的类型转化就非常容易了。比如在Android NDK探究奥秘一中建立的项目中。增加一个native方法:
package com.xiaoyunchengzhu.jnidemo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; public class MainActivity extends AppCompatActivity { // Used to load the 'native-lib' library on application startup. static { System.loadLibrary("native-lib"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = (TextView) findViewById(R.id.sample_text); tv.setText("数值相加为:"+sub(6,7)); } } /** * A native method that is implemented by the 'native-lib' native library, * which is packaged with this application. */ public native String stringFromJNI(); public native int sub(int m,int n); }那么在C中就可以直接写
jint Java_com_xiaoyunchengzhu_jnidemo_MainActivity_sub(JNIEnv *env, jobject instance, jint m, jint n) { int k=m+n; return k; } 因为jint本来就是C语言中int类型定义的类型。所以可以通用。在Jni本地代码中其它基本类型也是如此,jdouble可以直接当作double类型来用。jlong可以当作long类型来用。 jboolean、jbyte、jchar就需要当作其它各自对应C定义的类型来用了。 虽然可以这么通用,但是建议在C/C++中的运算代码还是先按照C的类型来写,最后需要和Java交互返回的数据,或者传入的数据,再转化成Java映射到本地的类型。
Java数组对象类型转化
在Android NDK探究奥秘二中也列出了一些一些Java对象类型。先看Java对象映射到本地类型:对象的转换基本上都是由JNIEnv结构里面的函数还执行的。
这些类型都是在C++中定义的,可以看出这些jobject 、jclass、jstring、jarray等归根结底都是_jobject。这些Java对象是怎么转化的呢?
jstring
首先看一下最通用的Java String类型,这个类比较特殊,单独拿出来说,在本地中是jstring,实现上面的stringFromJni方法在本地是:
jstring Java_com_xiaoyunchengzhu_jnidemo_MainActivity_stringFromJNI(JNIEnv *env, jobject /* this */) { return env->NewStringUTF("hello jni"); } jstirng是由JNIEnv这个结构体来转换的 char*。也就是说是 从本地的char*转换到jstring的实现。那么从jstring转换到char*呢。比如java 代码中增加了一个native方法public native String stringFromJNI(String value); 那么在C中value转换成C中char*来供C计算,比如字符串拼接:jstring Java_com_xiaoyunchengzhu_jnidemo_MainActivity_stringFromJNI(JNIEnv *env, jobject /* this */,jstring value) {jboolean *jboolean1; char *b="转换的值是:"; const char *a=env->GetStringUTFChars(value,jboolean1); char *c=(char*)malloc(strlen(a)+strlen(b)+1); strcpy(c,b); strcat(c,a); return env->NewStringUTF(c);}
通过JNIEnv 调用GetStringUtfChars来转换成const char* 类型。这里是获取的utfchar还有一个函数GetStringChars.不转码的。
里面还有许多有关于jstring的函数,获取jstring的长度,获取utfstring的长度,还有ReleaseString,RealeaseS他rinUtf等。在以后的操作中都会用到。有关于分配
空间,释放空间的问题。下面是对jstring操作的函数:jstring NewString(const jchar* unicodeChars, jsize len) 这个是new一个jstring类。jsize GetStringLength(jstring string) 获取jstring的长度。const jchar* GetStringChars(jstring string, jboolean* isCopy) 从jstring到 const char* 的转换。void ReleaseStringChars(jstring string, const jchar* chars) 释放 jstringjstring NewStringUTF(const char* bytes) 这个是new一个UTF jstring类。不带 UTF的操作和带UTF的操作的转换大家都理解吧。不多说了。jsize GetStringUTFLength(jstring string) 获取UTF jstring的长度const char* GetStringUTFChars(jstring string, jboolean* isCopy) 从UTF jstring到 const char* 的转换。
void ReleaseStringUTFChars(jstring string, const char* utf) 释放 UTF jstring
Array
下面是int数组的转换例子: 在Java 代码中声明一个native方法:public native int[] getArray(int size);在本地实现方法为:
jintArray Java_com_xiaoyunchengzhu_jnidemo_MainActivity_getArray(JNIEnv *env, jobject instance, jint size) { // TODO jintArray jintArray1; int f[size]; for (int i=0;i<size;i++){ f[i]=i; } jintArray1=env->NewIntArray(size); env->SetIntArrayRegion(jintArray1,0,size,f); return jintArray1; } 这是一个简单的数组初始化。由 本地C的int数组进行初始化 再转为jintArray。 其它的数组也是相似:jbooleanArray NewBooleanArray(jsize length)jbyteArray NewByteArray(jsize length)jcharArray NewCharArray(jsize length)jshortArray NewShortArray(jsize length)jintArray NewIntArray(jsize length)jlongArray NewLongArray(jsize length)jfloatArray NewFloatArray(jsize length)jdoubleArray NewDoubleArray(jsize length)这是jobjectArray:jobjectArray NewObjectArray(jsize length, jclass elementClass,jobject initialElement) 从数组赋值给array 为:void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len,const jboolean* buf)void SetByteArrayRegion(jbyteArray array, jsize start, jsize len,const jbyte* buf)void SetCharArrayRegion(jcharArray array, jsize start, jsize len,const jchar* buf)void SetShortArrayRegion(jshortArray array, jsize start, jsize len,const jshort* buf)void SetIntArrayRegion(jintArray array, jsize start, jsize len,const jint* buf)void SetLongArrayRegion(jlongArray array, jsize start, jsize len,const jlong* buf)void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len,const jfloat* buf)void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, const jdouble* buf)这是jobjectArray:void SetObjectArrayElement(jobjectArray array, jsize index, jobject value)
下面是从jintArray到C int*的转换:
在Java中声明native方法:public native int[] getAddArray(int[] m); 在本地代码中实现为:jintArray Java_com_xiaoyunchengzhu_jnidemo_MainActivity_getAddArray(JNIEnv *env, jobject instance, jintArray m) { jintArray jintArray1; int *m_ = env->GetIntArrayElements(m, NULL); int f[env->GetArrayLength(m)]; for (int i=0;i<env->GetArrayLength(m);i++){ f[i]=m_[i]+1; } jintArray1=env->NewIntArray(env->GetArrayLength(m)); env->SetIntArrayRegion(jintArray1,0,env->GetArrayLength(m),f); return jintArray1; } 其中方法的功能是发int数组每一个数据都加一。方法 GetIntArrayElements(jintArray array, jboolean* isCopy)就是jintArray到本地 int* 类型转换。这是jintArray的。 那么其它的Array也是同样道理,转换方法为:jboolean* GetBooleanArrayElements(jbooleanArray array, jboolean* isCopy)jbyte* GetByteArrayElements(jbyteArray array, jboolean* isCopy)jchar* GetCharArrayElements(jcharArray array, jboolean* isCopy)jshort* GetShortArrayElements(jshortArray array, jboolean* isCopy)jlong* GetLongArrayElements(jlongArray array, jboolean* isCopy)jfloat* GetFloatArrayElements(jfloatArray array, jboolean* isCopy)jdouble* GetDoubleArrayElements(jdoubleArray array, jboolean* isCopy) 上面都是基本类型的数组,那么object类型的数组就不同了:jobject GetObjectArrayElement(jobjectArray array, jsize index) 返回的是一个集合的一个元素。这些操作都有释放函数,比如在上述例子:数组的每个元素加一的函数中,如果不用了,释放函数调用:env->ReleaseIntArrayElements(m, m_, 0);这些数组的函数为:
void ReleaseBooleanArrayElements(jbooleanArray array, jboolean* elems,jint mode)void ReleaseByteArrayElements(jbyteArray array, jbyte* elems,jint mode)
void ReleaseCharArrayElements(jcharArray array, jchar* elems,jint mode)
void ReleaseShortArrayElements(jshortArray array, jshort* elems,jint mode)
void ReleaseIntArrayElements(jintArray array, jint* elems, jint mode)
void ReleaseLongArrayElements(jlongArray array, jlong* elems,jint mode)
void ReleaseFloatArrayElements(jfloatArray array, jfloat* elems,jint mode)
void ReleaseDoubleArrayElements(jdoubleArray array, jdouble* elems,jint mode)
这些就是常用的Java 基本类型和基本类型数组与 本地代码类型转换的方式。类型转化是Java和本地 交互的基础,有了这些才能互相通讯。另外,里面有关于jobject类型没有没有详细说明,是因为jobject类要拿出来单独说。Java中的类,变量 有私有变量,公有变量,保护变量,还有静态变量,非静态变量;构造方法;还有多种修饰的方法,这些在本地的转换还是比较复杂的。