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


        在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) 释放 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值