当前位置:操作系统 > 安卓/Android >>

[Android应用开发]-(15)JNI----基本数据类型

这篇拙文将通过实例的方式来简易学习JNI的数据类型。任何语言都有其基本的数据类型,要深入了解,必须要了解最基础的东西,在JNI中,我们会问:Java语言中的数据类型是如何映射到C/C++本地语言中的呢?

目录:

   1. 一个简单的实例分析

    2. Java与JNI数据类型的映射

    3. 字符串的处理

    4. 数组的处理

 \


1. 一个简单的实例分析编程中,向函数传参和函数返回值是很普遍的事情,这里就通过几个实例介绍这些技术。先通过一个简单的实例来入门吧。这里扩充HelloWorld.java,先打印一段字符串,然后等待用户输入,看代码:(这里我只列出C的代码)

[cpp]
<SPAN style="FONT-SIZE: 16px">  JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *, jobject, jstring);//(这串代码怎么来的,请看【Android应用开发】-(14)JNI----经典实例分析 )</SPAN> 

  JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *, jobject, jstring);//(这串代码怎么来的,请看【Android应用开发】-(14)JNI----经典实例分析 )
我们看getLine这个函数接收三个参数JNIEnv,jobject,jstring。其中JNIEnv包括JNI的函数表,如下图:

jobject的意义取决于该方法是静态的还是实例方法,当本地方法作为一个方法时,jobject相当于对象本身,即this。当本地方法作为一个静态方法时,指向所在类。在本实例中,getline是一个本地实例方法实现,所以jobject指向对象本身。

 

2. 类型的映射

按数据类型来说,java中有两种数据类型,基本的数据类型(int float,char),另一种是引用类型(实例、数组)。在本地方法(native 声明的方法)中声明的参数类型,在JNI中都有对应的类型。

Java与JNI基本类型的映射很直接,请看下表:

Java                                                
 Native(jni.h)                                   
 
boolean
 jboolean
 
byte
 jbyte
 
char
 jchar
 
short
 jshort
 
Int
 jint
 
long
 jlong
 
Float
 jfloat
 
double
 jdouble
 


除了这些类型之外还定义了jstring,jclass,jobjectArray等结构。他们都继承自jobject.


相比基本类型,对象类型的传递要复杂很多。Java层的对象对象以(opaque references)指针的形势传递到JNI层。opaque references是C的指针类型,它指向JavaVM内部数据结构。使用这种指针的目的是:不希望JNI用户了解JAVAVM内部数据结构。对opaque references所指结构的操作,都要通过JNI方法进行。比如,”java.lang.String”对象,JNI层对于的类型为jstring,对该opaque references的操作要通过JNIEnv->GetStringUTFChars进行。这里需要注意的是:编程的过程中一定要按照原则编程,千万不要为了效率或者容易渠道某个值而绕过JNI,直接操作opaque references。

 

3. 字符串处理

1) 实例

现在我们回到实例中,看如何处理从java传过去的String类型,请看下面代码?

[cpp]
JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){ 
    Printf(“%s”,prompt); 

JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){
 Printf(“%s”,prompt);
}
很抱歉,出错了:incorrect use of jstring as a char* pointer。

这里需要使用对于JNI函数把jstring装好为C/C++字符串。JNI支持Unicode/UTF-8字符编码互转。Unicode 以16-bits值编码;UTF-8是一种以字节为单位变长格式的字符编码,并与7-bits ASCII码兼容。UTF-8字串与C字串一样,以NULL('\0')做结束符, 当UTF-8包含非ASCII 码字符时,以'\0'做结束符的规则不变。7-bit ASCII字符的取值范围在 1-127之间,这些 字符的值域与UTF-8中相同。当最高位被设置时,表示多字节编码。如下,调用GetStringUTFChars,把一个Unicode字串转成UTF-8格式字串,如果你确定字串只包含7-bit ASCII字符。这个字串可以使用C库中的相关函数,如printf.

[cpp]
Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){ 
char buf[128];  
    const jbyte *str;  
    str =  (*env)->GetStringUTFChars(env, prompt, NULL);  
    if  (str == NULL) {  
      return NULL; /* OutOfMemoryError already thrown */  
    }  
    printf("%s , str);  
     (*env)->ReleaseStringUTFChars(env, prompt, str);  
    /* We assume here that the user does not type more than 127 characters */  
    scanf("%127s , buf);  
  return  (*env)->NewStringUTF(env, buf); 
 } 

Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){
char buf[128];
    const jbyte *str;
    str =  (*env)->GetStringUTFChars(env, prompt, NULL);
    if  (str == NULL) {
      return NULL; /* OutOfMemoryError already thrown */
    }
    printf("%s , str);
     (*env)->ReleaseStringUTFChars(env, prompt, str);
    /* We assume here that the user does not type more than 127 characters */
    scanf("%127s , buf);
  return  (*env)->NewStringUTF(env, buf);
 }

这里一定要检测GetStringUTFChars的返回值,因为调用该函数会有内存分配操作。失败有该函数返回NULL,并抛出OutOfMemoryError异常。发生异常不会改变代码的执行轨迹,所以当返回Null时要及时处理异常。

1) 释放GetStringUTFChars调用时的内存使用。ReleaseStringUTFChars

2) 构造新的字符串使用JNIEnv->NewStringUTF,同样的,如果没有足够的内存也会抛出OutOfMemoryError异常。

3) 其他字符串操作方法

GetStringChars是有Java 内部Unicode到本地UTF-8的转换函数,可以调用 GetStringLength,获得以Unicode编码的字串长度。也可以使用strlen计算 GetStringUTFChars的返回值,得到字串长度。

const jchar * GetStringChars(JNIEnv *env, jstring str, jboolean *isCopy);

具体的使用请参考JNI详解16-20页

4. 数组的操作

Java部分代码很简单,不贴出来了。我们直接看C代码。

[cpp]
JNIEXPORT jint JNICALL Java_org_winplus_basetype_IntArray_sumArray(JNIEnv *env, 
        jobject obj, jintArray arr) { 
    // 我们不能直接这样操作。  
    /* This program is illegal! */ 
    /*int i, sum = 0;
     for (i = 0; i < 10; i++) {
     sum += arr[i];
     }*/ 
 
    //////////////////////////////////示例代码1///////////////////////////  
 
//  jint buf[10];  
//  jint i, sum = 0;  
//  (*env)->GetIntArrayRegion(env, arr, 0, 10, buf);  
//  for (i = 0; i < 10; i++) {  
//      sum += buf[i];  
//  }  
//  return sum;  
 
    ///////////////////////////////////示例代码2///////////////////////////&nb

补充:移动开发 , Android ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,