Android NDK探究奥秘三:Jni类型转化

来源:互联网 发布:http aq.qq.com js 编辑:程序博客网 时间:2024/06/05 19:36


        在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计算,比如字符串拼接:
jstringJava_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) 释放 jstring 

jstring NewStringUTF(const char* bytes)    这个是new一个UTF jstring类。
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 
不带 UTF的操作和带UTF的操作的转换大家都理解吧。不多说了。




         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中的类,变量 有私有变量,公有变量,保护变量,还有静态变量,非静态变量;构造方法;还有多种修饰的方法,这些在本地的转换还是比较复杂的。




   










   


0 0
原创粉丝点击