jni应用(学习以及应用)

来源:互联网 发布:动画剧场版神作 知乎 编辑:程序博客网 时间:2024/06/11 06:31

                  

要素 1该函数大全是基于C语言方式的,对于C++方式可以直接转换,例如,对于生成一个jstring类型的方法转换分别如下:

                    C编程环境中使用方法为:(*env) ->NewStringUTF(env, "123") ;

                    C++编程环境中(例如,VC下)则是 env ->NewStringUTF("123") ;             (使用起来更简单)

 

           2、关于下列有些函数中:*isCopy    的说明,例如,如下函数:                     

                           const char* GetStringUTFChars(JNIEnv*env,jstring string, jboolean *isCopy);  

 

        对第三个参数 jboolean *isCopy说明如下:

             当从JNI函数GetStringUTFChars函数中返回得到字符串B时,如果B是原始字符串java.lang.String的一份拷贝,

      isCopy 被赋值为JNI_TRUE。如果B是和原始字符串指向的是JVM中的同一份数据isCopy 被赋值为JNI_FALSE

     isCopy JNI_FALSE时,本地代码绝不能修改字符串的内容,否则JVM中的原始字符串也会被修改,这会打破Java语言

     中字符串不可变的规则。

           通常,我们不必关心JVM是否会返回原始字符串的拷贝,只需要为isCopy传递NULL作为参数

                                                                                                          

----     以上内容来自 JNI编程指南》

http://blog.csdn.net/qinjuning

 

 

 

 

 

 

 

 

 

一、类操作             

                          

jclass DefineClass (JNIEnv*env, jobject loader,   const jbyte *buf , jsize bufLen);                

    功能:从原始类数据的缓冲区中加载类。             

    参数 env        JNI接口指针。           

                loader    分派给所定义的类的类加载器。          

                buf       包含 .class文件数据的缓冲区。               

                bufLen  缓冲区长度。          

    返回值:返回 Java类对象。如果出错则返回NULL            

    抛出 ClassFormatError      如果类数据指定的类无效。                

     ClassCircularityError  如果类或接口是自身的超类或超接口。              

     OutOfMemoryError  如果系统内存不足。                  

                      

  jclass FindClass (JNIEnv *env, const char*name);                

     功能:该函数用于加载本地定义的类。它将搜索由CLASSPATH环境变量为具有指定名称的类所指定的目录和 zip文件            

     参数env    JNI接口指针。            

              name 类全名(即包名后跟类名,之间由"/"分隔).如果该名称以“[(数组签名字符)打头,则返回一个数组类。         

     返回值:返回类对象全名。如果找不到该类,则返回 NULL               

     抛出 ClassFormatError如果类数据指定的类无效。                

    ClassCircularityError      如果类或接口是自身的超类或超接口。                

    NoClassDefFoundError  如果找不到所请求的类或接口的定义。            

  OutOfMemoryError      如果系统内存不足。                  

 

  jclass GetObjectClass (JNIEnv *env, jobject obj); 

     功能通过对象获取这个类。该函数比较简单,唯一注意的是对象不能为NULL,否则获取的class肯定返回也为NULL     

     参数  env   JNI接口指针。            

                obj  Java类对象实例。        

  

  jclass GetSuperclass (JNIEnv*env, jclassclazz);          

    功能:获取父类或者说超类 如果 clazz 代表类class而非类 object,则该函数返回由 clazz所指定的类的超类。如果 clazz 

    指定类 object或代表某个接口,则该函数返回NULL          

    参数  env   JNI接口指针。            

               clazz  Java类对象。            

    返回值    clazz 所代表的类的超类或 NULL              

                        

 jboolean IsAssignableFrom (JNIEnv *env, jclass clazz1,  jclass clazz2);          

   功能:确定 clazz1的对象是否可安全地强制转换为clazz2            

   参数  env  JNI接口指针。            

             clazz1第一个类参数。               

             clazz2第二个类参数。               

   返回值  下列某个情况为真时返回 JNI_TRUE              

                   1 第一及第二个类参数引用同一个 Java类。              

                   2第一个类是第二个类的子类。             

                   3第二个类是第一个类的某个接口。    

 

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

         

、异常操作                  

                      

  jint Throw(JNIEnv*env, jthrowable obj);         

  功能:抛出 java.lang.Throwable对象。                 

   参数 env  JNI接口指针。            

           obj   java.lang.Throwable对象。         

      返回值  成功时返回 0,失败时返回负数。             

      抛出    java.lang.Throwable对象 obj           

               

  jint ThrowNew (JNIEnv *env,  jclass clazz,  const char *message);           

    功能:利用指定类的消息(由 message指定)构造异常对象并抛出该异常。               

    参数 env    JNI接口指针。            

               clazz java.lang.Throwable的子类。          

               message  用于构造java.lang.Throwable对象的消息。           

    返回值 成功时返回 0,失败时返回负数。             

    抛出  新构造的 java.lang.Throwable对象。                

                  

 jthrowable ExceptionOccurred (JNIEnv*env);              

    功能:确定是否某个异常正被抛出。在平台相关代码调用 ExceptionClear() Java 代码处理该异常前,异常将始终保持

        抛出状态。                  

    参数  env  JNI接口指针。            

    返回值 返回正被抛出的异常对象,如果当前无异常被抛出,则返回NULL           

                    

 void ExceptionDescribe (JNIEnv*env);         

    功能:将异常及堆栈的回溯输出到系统错误报告信道(例如 stderr)。该例程可便利调试操作。               

    参数env   JNI接口指针。            

                   

 void ExceptionClear (JNIEnv *env);               

   功能:清除当前抛出的任何异常。如果当前无异常,则此例程不产生任何效果。                  

   参数 env   JNI接口指针。            

                 

  void FatalError (JNIEnv*env, const char*msg);           

   功能:抛出致命错误并且不希望虚拟机进行修复。该函数无返回值。             

   参数  env   JNI接口指针。            

              msg  错误消息。          

             

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

     

 

 

 

 

 

 

三、全局及局部引用                  

  jobject NewGlobalRef (JNIEnv *env, jobjectobj);         

    功能:创建 obj参数所引用对象的新全局引用。obj参数既可以是全局引用,也可以是局部引用。全局引用通过调用 

         DeleteGlobalRef()来显式撤消。          

    参数env   JNI接口指针。            

               obj    全局或局部引用。                 

    返回值 返回全局引用。如果系统内存不足则返回 NULL          

                    

 void DeleteGlobalRef (JNIEnv *env, jobjectglobalRef);                 

    功能删除 globalRef所指向的全局引用。         

    参数 env    JNI接口指针。            

               globalRef  全局引用。         

                            

 void  DeleteLocalRef (JNIEnv *env, jobjectlocalRef);          

     功能删除 localRef所指向的局部引用。             

     参数 env   JNI接口指针。            

                 localRef 局部引用。            

             

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    

 

 

 

 

 

 

 

 

 

 

 

 

四、对象操作         

         

 jobject AllocObject (JNIEnv *env, jclassclazz);              

    功能:分配新 Java对象而不调用该对象的任何构造函数。返回该对象的引用。clazz参数务必不要引用数组类。               

    参数 env  JNI接口指针。            

              clazz  Java类对象。            

    返回值 返回 Java对象。如果无法构造该对象,则返回NULL                

    抛出 InstantiationException:如果该类为一个接口或抽象类。                

               OutOfMemoryError:如果系统内存不足。                  

                        

  jobject NewObject (JNIEnv *env,  jclass clazz,  jmethodID methodID, ...);   //参数附加在函数后面            

  jobject NewObjectA (JNIEnv *env, jclassclazz,  jmethodID methodID, jvalue *args);    //参数以指针形式附加           

  jobjectNewObjectV (JNIEnv *env , jclassclazz,  jmethodIDmethodID, va_list args);    //参数以"链表"形式附加            

 

  功能:构造新 Java对象。方法 ID指示应调用的构造函数方法。注意:该 ID特指该类class的构造函数ID必须通过调用 

      GetMethodID()获得,且调用时的方法名必须为<init>,而返回类型必须为 void (V)clazz参数务必不要引用数组类。 

  参数  env  JNI接口指针。            

             clazz  Java类对象。            

             methodID构造函数的方法 ID               

    NewObject 的其它参数:  传给构造函数的参数,可以为空                 

    NewObjectA的其它参数: args:传给构造函数的参数数组。              

    NewObjectV的其它参数: args:传给构造函数的参数 va_list       

          

  返回值 返回 Java对象,如果无法构造该对象,则返回NULL                

  抛出   InstantiationException  如果该类为接口或抽象类。                

             OutOfMemoryError  如果系统内存不足。                  

             构造函数抛出的任何异常。                  

                             

 jclass GetObjectClass (JNIEnv *env, jobjectobj);         

  功能:返回对象的类。             

  参数 env  JNI接口指针。            

             obj  Java对象(不能为 NULL)。               

  返回值 返回 Java类对象。              

                        

 jboolean IsInstanceOf (JNIEnv*env, jobject obj, jclass clazz);            

   功能:测试对象是否为某个类的实例。                  

   参数  env  JNI接口指针。            

               obj Java对象。           

               clazzJava类对象。            

   返回值:如果可将 obj强制转换为 clazz,则返回 JNI_TRUE。否则返回 JNI_FALSENULL对象可强制转换为任何类。           

                         

 jbooleanIsSameObject (JNIEnv*env, jobjectref1, jobject ref2);           

   功能:测试两个引用是否引用同一 Java对象。         

   参数  env  JNI接口指针。            

              ref1  Java对象。                  

              ref2   Java对象。                  

   返回值 如果 ref1 ref2 引用同一 Java对象或均为 NULL,则返回 JNI_TRUE。否则返回 JNI_FALSE         

        

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    

                  

五、 字符串操作             

                               

 jstring  NewString (JNIEnv *env, const jchar *unicodeChars,  jsize len);         

    功能:利用 Unicode字符数组构造新的 java.lang.String对象。               

    参数   envJNI接口指针。            

                 unicodeChars:指向 Unicode字符串的指针。         

                 lenUnicode字符串的长度。             

    返回值 Java字符串对象。如果无法构造该字符串,则为NULL             

    抛出 OutOfMemoryError:如果系统内存不足。                 

                            

 jsize  GetStringLength (JNIEnv*env, jstringstring);            

   功能:返回 Java字符串的长度(Unicode 字符数)。                 

   参数  envJNI接口指针。            

               stringJava字符串对象。          

   返回值 Java字符串的长度。            

                            

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

  功能:返回指向字符串的 Unicode字符数组的指针。该指针在调用 ReleaseStringchars()前一直有效。          

        如果 isCopy非空,则在复制完成后将 *isCopy设为 JNI_TRUE。如果没有复制,则设为JNI_FALSE  

  参数   envJNI接口指针。            

               stringJava字符串对象。          

               isCopy:指向布尔值的指针。               

   返回值   指向 Unicode 字符串的指针,如果操作失败,则返回NULL               

                                  

 void  ReleaseStringChars (JNIEnv *env, jstring string,  const jchar *chars);                 

   功能:通知虚拟机平台相关代码无需再访问 chars。参数chars是一个指针,可通过 GetStringChars() string 获得。    

   参数 envJNI接口指针。            

             stringJava字符串对象。          

             chars:指向 Unicode字符串的指针。               

                      

 jstring  NewStringUTF (JNIEnv*env, const char*bytes);            

  功能:利用 UTF-8字符数组构造新 java.lang.String对象。               

  参数 envJNI接口指针。如果无法构造该字符串,则为 NULL         

             bytes:指向 UTF-8字符串的指针。          

   返回值Java字符串对象。如果无法构造该字符串,则为NULL             

  抛出  OutOfMemoryError:如果系统内存不足。                 

                          

 jsize  GetStringUTFLength (JNIEnv *env, jstringstring);              

   功能:以字节为单位返回字符串的 UTF-8长度。                

   参数   envJNI接口指针。            

              stringJava字符串对象。          

  返回值  返回字符串的 UTF-8

 

 const char* GetStringUTFChars (JNIEnv*env,jstring string, jboolean *isCopy);          

   功能:返回指向字符串的 UTF-8字符数组的指针。该数组在被ReleaseStringUTFChars()释放前将一直有效。    如果 isCopy 

     不是 NULL*isCopy在复制完成后即被设为 JNI_TRUE。如果未复制,则设为 JNI_FALSE             

  参数  envJNI接口指针。            

             stringJava字符串对象。          

             isCopy:指向布尔值的指针。               

   返回值  指向 UTF-8 字符串的指针。如果操作失败,则为 NULL             

                          

 void  ReleaseStringUTFChars (JNIEnv *env, jstring string,  const char *utf);              

  功能:通知虚拟机平台相关代码无需再访问 utfutf参数是一个指针,可利用 GetStringUTFChars()获得。                 

   参数   envJNI接口指针。            

              stringJava字符串对象。          

              utf:指向 UTF-8字符串的指针。               

 

 

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

         

六、数组操作                         

 

 jsize GetArrayLength (JNIEnv*env, jarrayarray);                 

  功能:返回数组中的元素数。                  

  参数  envJNI接口指针。            

             arrayJava数组对象。                

  返回值 数组的长度。                 

                           

 jarray NewObjectArray (JNIEnv*env, jsize length,  jclass elementClass, jobject initialElement);          

   功能:构造新的数组,它将保存类 elementClass中的对象。所有元素初始值均设为 initialElement               

   参数 envJNI接口指针。            

            length:数组大小。               

            elementClass:数组元素类。               

            initialElement:初始值。    可以为NULL           

  返回值Java数组对象。如果无法构造数组,则为 NULL                 

  抛出  OutOfMemoryError:如果系统内存不足。                 

  

  说明使用该函数时,为了便于易操作性,我们一般可以用jobjectArray数组类型或得返回值,例如:

                jobjectArray objArray =env->NewObjectArray ( );

                //操作该对象

                env->GetObjectArrayElement (objArray, 0);//获得该object数组在索引0处的值 ,(可以强制转换类型).

 

 jobject GetObjectArrayElement (JNIEnv *env,   jobjectArray array, jsizeindex);                

   功能:返回 Object数组的元素。          

  参数   envJNI接口指针。            

               arrayJava数组。                

               index:数组下标。                 

  返回值 Java对象。            

  抛出 ArrayIndexOutOfBoundsException:如果 index 不是数组中的有效下标。             

                 

 void  SetObjectArrayElement (JNIEnv *env, jobjectArray array,  jsize index,jobject value);                

  功能:设置 Object数组的元素。          

   参数  envJNI接口指针。            

             arrayJava数组。                

              index:数组下标。                 

              value:新值。                 

   抛出 ArrayIndexOutOfBoundsException:如果index不是数组中的有效下标。            

             ArrayStoreException:如果 value的类不是数组元素类的子类。           

                      

    New<PrimitiveType>Array方法类型      

         

  NativeType New<PrimitiveType>Array (JNIEnv *env, ArrayType array, jboolean*isCopy);                 

 

    说明用于构造新基本类型数组对象的一系列操作。下表说明了特定的基本类型数组构造函数。用户应把

   New<PrimitiveType>Array替换为某个实际的基本类型数组构造函数例程名(见下表),然后将 ArrayType替换为

 该例程相应的数组类型。

     参数  env JNI 接口指针。           

                length:数组长度。               

     返回值  Java数组。如果无法构造该数组,则为 NULL

         

          New<PrimitiveType>Array 方法组               数组类型        

                 NewBooleanArray()                          jbooleanArray 

                 NewByteArray()                                jbyteArray       

                 NewCharArray()                              jcharArray       

                 NewShortArray()                              jshortArray      

                 NewIntArray()                                  jintArray 

                 NewLongArray()                              jlongArray        

                 NewFloatArray()                              jfloatArray       

                NewDoubleArray()                            jdoubleArray   

                 

                  

 Get<PrimitiveType>ArrayElements 方法类型       

 

 NativeType *Get<PrimitiveType>ArrayElements (JNIEnv *env, ArrayType array, jboolean*isCopy);                 

  说明:一组返回基本类型数组体的函数。结果在调用相应的 Release<PrimitiveType>ArrayElements()函数前将一直有效。

    由于返回的数组可能是 Java数组的副本,因此对返回数组的更改不必在基本类型数组中反映出来,直到调用了

    Release<PrimitiveType>ArrayElements() 如果 isCopy不是 NULL*isCopy在复制完成后即被设为 JNI_TRUE。如果

    未复制,则设为JNI_FALSE         

  使用说明:   

     Get<PrimitiveType>ArrayElements替换为表中某个实际的基本类型元素访问器例程名。             

        将 ArrayType替换为对应的数组类型。             

        将 NativeType替换为该例程对应的本地类型。               

    参数   envJNI接口指针。           

               arrayJava字符串对象。           

               isCopy:指向布尔值的指针。               

   返回值    返回指向数组元素的指针,如果操作失败,则为 NULL          

             

    不管布尔数组在 Java虚拟机中如何表示,GetBooleanArrayElements()将始终返回一个 jbooleans 类型的指针,其中每一

 字节代表一个元素(开包表示)。内存中将确保所有其它类型。

         

           Get<PrimitiveType>ArrayElements例程        数组类型                 本地类型

                GetBooleanArrayElements()                  jbooleanArray            jboolean

                 GetByteArrayElements()                       jbyteArray                 jbyte

                 GetCharArrayElements()                      jcharArray                 jchar

                 GetShortArrayElements()                     jshortArray                jshort

                 GetIntArrayElements()                         jintArray                    jint

                 GetLongArrayElements()                      jlongArray                 jlong

                 GetFloatArrayElements()                      jfloatArray                 jfloat

                GetDoubleArrayElements()                    jdoubleArray             jdouble

      

                  

     Release<PrimitiveType>ArrayElements 方法类型                

 

  void  Release<PrimitiveType>ArrayElements (JNIEnv *env, ArrayType array, NativeType*elems,jintmode);            

     功能:通知虚拟机平台相关代码无需再访问 elems的一组函数。elems 参数是一个通过使用对应的

       Get<PrimitiveType>ArrayElements()函数由 array 导出的指针。必要时,该函数将把对 elems的修改复制回基本

       类型数组。mode参数将提供有关如何释放数组缓冲区的信息。如果elems不是 array 中数组元素的副本,mode将无效。

       否则,mode将具有下表所述的功能:             

                       模式                                        动作        

                        0                           复制回内容并释放elems缓冲区      

                  JNI_COMMIT              复制回内容但不释放elems缓冲区  

                  JNI_ABORT                 释放缓冲区但不复制回变化        

      多数情况下,编程人员将把“0”传给 mode参数以确保固定的数组和复制的数组保持一致。其它选项可以使编程人员进一步

  控制内存管理,但使用时务必慎重。             

    使用说明:

         ArrayType替换为对应的数组类型。             

         NativeType替换为该例程对应的本地类型。               

    

   参数 envJNI接口指针。            

             arrayJava数组对象。                

             elems:指向数组元素的指针。           

             mode:释放模式。      

 

         Release<PrimitiveType>ArrayElements 方法组        数组类型            本地类型

             ReleaseBooleanArrayElements()                    jbooleanArray       jboolean

              ReleaseByteArrayElements()                         jbyteArray             jbyte

              ReleaseCharArrayElements()                         jcharArray             jchar

             ReleaseShortArrayElements()                       jshortArray            jshort

             ReleaseIntArrayElements()                            jintArray                jint

              ReleaseLongArrayElements()                       jlongArray            jlong

            ReleaseFloatArrayElements()                       jfloatArray           jfloat

             ReleaseDoubleArrayElements()                  jdoubleArray         jdouble

          

                  

    Get<PrimitiveType>ArrayRegion 方法类型          

 

  void  Get<PrimitiveType>ArrayRegion (JNIEnv *env, ArrayType array,  jsize start,jsize len, NativeType*buf);            

    功能:将基本类型数组某一区域复制到缓冲区中的一组函数。                    

      使用说明:        

               Get<PrimitiveType>ArrayRegion替换为下表的某个实际基本类型元素访问器例程名。

               ArrayType替换为对应的数组类型。             

               NativeType替换为该例程对应的本地类型。     

   参数     envJNI接口指针。            

                arrayJava指针。                

                start:起始下标。                  

                len:要复制的元素数。                 

                buf:目的缓冲区。                

   抛出  ArrayIndexOutOfBoundsException:如果区域中的某个下标无效。  

          

  方法族如下:                         

                    Get<PrimitiveType>ArrayRegion方法          数组类型            本地类型

                        GetBooleanArrayRegion()                          jbooleanArray    jboolean

                       GetByteArrayRegion()                               jbyteArray          jbyte

                       GetCharArrayRegion()                              jcharArray          jchar

                       GetShortArrayRegion()                             jshortArray          jhort

                        GetIntArrayRegion()                                 jintArray              jint

                       GetLongArrayRegion()                              jlongArray          jlong

                        GetFloatArrayRegion()                              jfloatArray         jloat

                        GetDoubleArrayRegion()                          jdoubleArray    jdouble

          

                  

        Set<PrimitiveType>ArrayRegion 方法类型          

 

 void  Set<PrimitiveType>ArrayRegion (JNIEnv *env, ArrayType array,   jsizestart, jsize len, NativeType*buf);            

    功能:将基本类型数组的某一区域从缓冲区中复制回来的一组函数。             

        使用说明:   Set<PrimitiveType>ArrayRegion替换为表中的实际基本类型元素访问器例程名。          

                           ArrayType替换为对应的数组类型。             

                           NativeType替换为该例程对应的本地类型。               

    参数 envJNI接口指针。            

              array: Java数组。              

              start:起始下标。                  

              len:要复制的元素数。                 

              buf:源缓冲区。            

    抛出 ArrayIndexOutOfBoundsException:如果区域中的某个下标无效。 

     

                  Set<PrimitiveType>ArrayRegion 方法族           数组类型            本地类型

                       SetBooleanArrayRegion()                         jbooleanArray     jboolean

                       SetByteArrayRegion()                               jbyteArray           jbyte

                        SetCharArrayRegion()                              jcharArray          jchar

                       SetShortArrayRegion()                             jshortArray          jshort

                       SetIntArrayRegion()                                  jintArray             jint

                        SetLongArrayRegion()                              jlongArray           jlong

                        SetFloatArrayRegion()                              jfloatArray           jfloat

                        SetDoubleArrayRegion()                           jdoubleArray      jdouble

       

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

 

 

 

 

 

 

 

 

 

 

 

 

 六、访问对象的属性和方法                  

   

1、实例属性的访问

                           

  jfieldID  GetFieldID (JNIEnv*env, jclass clazz, const char *name, const char*sig);                

   功能:返回类的实例(非静态)域的属性 ID。该域由其名称及签名指定。访问器函数的Get<type>Field Set<type>Field

       系列使用域 ID检索对象域。GetFieldID()不能用于获取数组的长度域。应使用GetArrayLength()          

   参数  envJNI接口指针。            

               clazzJava类对象。            

              name:该属性的Name名称                

               sig  该属性的域签名。               

   返回值:属性ID。如果操作失败,则返回NULL              

   抛出 NoSuchFieldError:如果找不到指定的域。                  

             ExceptionInInitializerError:如果由于异常而导致类初始化程序失败。          

             OutOfMemoryError:如果系统内存不足。                 

               

   Get<type>Field例程               

 

  NativeType  Get<type>Field (JNIEnv*env, jobject obj, jfieldIDfieldID);                

    功能:该访问器例程系列返回对象的实例(非静态)域的值。要访问的域由通过调用GetFieldID()而得到的域 ID 指定。           

    参数   envJNI接口指针。            

                objJava对象(不能为 NULL)。               

                fieldID:有效的域 ID                 

   返回值   属性的内容。      

        Get<type>Field例程名        本地类型        

              GetObjectField()                 jobject     

               GetBooleanField()              jboolean  

              GetByteField()                    jbyte        

              GetCharField()                    jchar        

              GetShortField()                   jshort       

              GetIntField()                       jint  

              GetLongField()                    jlong         

              GetFloatField()                   jfloat        

               GetDoubleField()     jdouble    

 

   Set<type>Field 方法族 

        

  void  Set<type>Field (JNIEnv *env, jobject obj, jfieldIDfieldID,  NativeTypevalue);           

  功能该访问器例程系列设置对象的实例(非静态)属性的值。要访问的属性由通过调用SetFieldID()而得到的属性 ID指定。

   参数  envJNI接口指针。            

              objJava对象(不能为 NULL)。               

             fieldID:有效的域 ID                

              value:域的新值。   

     方法族 如下:                    

               Set<type>Field 方法族           本地类型        

                 SetObjectField()                   jobject     

                 SetBooleanField()                 jboolean  

                  SetByteField()                      jbyte        

                 SetCharField()                      jchar        

                 SetShortField()                    jshort       

                 SetIntField()                        jint  

                  SetLongField()                     jlong         

                 SetFloatField()                     jfloat        

                 SetDoubleField()                 jdouble    

 

 2、静态属性的访问 :也存在相同的方法,

 

       jfieldID  GetStaticFieldID (JNIEnv *env,jclass clazz, const char *name, const char*sig);     

       NativeType  GetStatic<type>Field (JNIEnv*env,jclass classzz , jfieldIDfieldID);           

            void  SetStatic<type>Field (JNIEnv *env,jclassclasszz, jfieldIDfieldID,  NativeTypevalue);           

   

   它们与实例属性的唯一区别在于第二个参数jclass classzz代表的是类引用,而不是类实例。

        

 3、调用实例方法 

      

  jmethodID GetMethodID(JNIEnv *env, jclass clazz,    const char*name, const char *sig);               

    功能:返回类或接口实例(非静态)方法的方法 ID。方法可在某个 clazz 的超类中定义,也可从 clazz继承。该方法由其名称

        和签名决定。 GetMethodID()可使未初始化的类初始化。要获得构造函数的方法 ID,应将 <init>作为方法名,同时将 

        void (V)作为返回类型。          

   参数  envJNI接口指针。            

               clazzJava类对象。            

               name:方法名。          

               sig:方法的签名。           

    返回值 方法 ID,如果找不到指定的方法,则为 NULL             

    抛出    NoSuchMethodError:如果找不到指定方法。            

                 ExceptionInInitializerError:如果由于异常而导致类初始化程序失败。          

                 OutOfMemoryError:如果系统内存不足。                  

                  

 Call<type>Method例程  Call<type>MethodA例程  Call<type>MethodV例程 

              

 NativeType Call<type>Method (JNIEnv*en v,  jobject obj , jmethodIDmethodID, ...);     //参数附加在函数后面,              

 NativeType Call<type>MethodA (JNIEnv *env, jobject obj, jmethodID methodID,jvalue *args);  //参数以指针形式附加  

  NativeType Call<type>MethodV (JNIEnv *env, jobject obj,jmethodID methodID, va_listargs); //参数以"链表"形式附加

     

  说明:这三个操作的方法用于从本地方法调用Java实例方法。它们的差别仅在于向其所调用的方法传递参数时所用的机制。   

      这三个操作将根据所指定的方法 ID调用 Java 对象的实例(非静态)方法。参数 methodID必须通过调用 GetMethodID() 

      来获得。当这些函数用于调用私有方法和构造函数时,方法 ID必须从obj 的真实类派生而来,而不应从其某个超类派生。

      当然,附加参数可以为空

  参数  envJNI接口指针。            

            objJava对象。           

            methodID:方法 ID                 

  返回值 返回调用 Java方法的结果。              

  抛出  执行 Java方法时抛出的异常。    

             

    

  下表根据结果类型说明了各个方法类型。用户应将Call<type>Method中的 type 替换为所调用方法的Java 类型(或使用表

 中的实际方法名),同时将 NativeType替换为该方法相应的本地类型。省略掉了其他两种类型。 


 

Java层返回值             方法族                 本地返回类型NativeType

 

 返回值为void    CallVoidMethod()   A / V        ()

 返回值为引用类型:     CallObjectMethod( )                            jobect

 返回值为boolean    CallBooleanMethod ( )                         jboolean

 返回值为byte          CallByteMethod( )                                jbyte

 返回值char           CallCharMethod( )                               jchar

 返回值short          CallShortMethod()                              jshort       

 返回值为int            CallIntMethod()                                     jint  

 返回值为long    CallLongMethod()                             jlong        

 返回值为float   CallFloatMethod()                                 jfloat        

返回值为double    CallDoubleMethod()                          jdouble    

 

 

 4、调用静态方法:也存在如下方法群,

 

       jfieldID  GetStaticMethodID (JNIEnv *env,jclass clazz, const char *name, const char*sig);     

       NativeType  Call<type>Method (JNIEnv*env,jclass classzz , jfieldIDfieldID);           

       

   它们与于实例方法的唯一区别在于第二个参数jclass classzz代表的是类引用,而不是类实例。

     

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

七、注册本地方法                  

                

  jint  RegisterNatives (JNIEnv*env, jclass clazz, const JNINativeMethod *methods,   jint nMethods);               

   功能:向 clazz参数指定的类注册本地方法。methods参数将指定 JNINativeMethod结构的数组,其中包含本地方法的名称、

   签名和函数指针。nMethods参数将指定数组中的本地方法数。JNINativeMethod结构定义如下所示:            

        typedef struct{                       

              char*name;          

              char*signature;               

             void*fnPtr;               

         }JNINativeMethod;                  

     函数指针通常必须有下列签名:                                  

             ReturnType (*fnPtr)(JNIEnv *env, jobject objectOrClass,...);                  

                  

   参数 envJNI接口指针。            

             clazzJava类对象。            

            methods:类中本地方法和具体实现方法的映射指针。               

            nMethods:类中的本地方法数。                 

   返回值  成功时返回 "0";失败时返回负数。         

   抛出  NoSuchMethodError:如果找不到指定的方法或方法不是本地方法。            

                  

 jint  UnregisterNatives (JNIEnv*env, jclassclazz);              

  功能取消注册类的本地方法。类将返回到链接或注册了本地方法函数前的状态。      该函数不应在常规平台相关代码中使用。

       相反,它可以为某些程序提供一种重新加载和重新链接本地库的途径。             

  参数  envJNI接口指针。            

            clazzJava类对象。            

  返回值 成功时返回“0”;失败时返回负数。  

 

 

Java存在两种数据类型:基本类型引用类型,大家都懂的

 

    JNI的世界里也存在类似的数据类型,与Java比较起来,其范围更具严格性,如下:

 

        1primitive types----基本数据类型,如:int float char等基本类型

        2referencetypes----引用类型,如:类、实例、数组。

 

      特别需要注意:数组 ------不管是对象数组还是基本类型数组,都作为reference types存在。

 

     1primitive types (基本数据类型)映射参见下表: 

 

               

 

        这些基本数据类型都是可以在Native层直接使用的

 

      2reference types (引用数据类型)映射参见下表

 

 Java类型              NativeType               描述

              

     注意   

        1、引用数据类型则不能直接使用,需要根据JNI函数进行相应的转换后,才能使用

        2、多维数组(包括二维数组)都是引用类型,需要使用 jobjectArray 类型存取其值

                例如:二维整型数组就是指向一位数组的数组,其声明使用方式如下:

                   

[java] view plaincopyprint?

1.  //获得一维数组 的类引用,即jintArray类型  

2.      jclass intArrayClass = env->FindClass("[I");   

3.      //构造一个指向jintArray类一维数组的对象数组,该对象数组初始大小为dimion  

4.      jobjectArray obejctIntArray  =  env->NewObjectArray(dimion ,intArrayClass , NULL);  

5.      ...//具体操作  

 

   另外,关于引用类型的一个继承关系如下,我们可以对具有父子关系的类型进行转换:

 类描述符

 

    类描述符是类的完整名称(包名+类名),将原来的 . 分隔符换成 / 分隔符。

           例如:在java代码中的java.lang.String类的类描述符就是java/lang/String

 

       其实,在实践中,我发现可以直接用该类型的域描述符取代,也是可以成功的。

              例如:       jclass intArrCls =env->FindClass("java/lang/String")

               等同于     jclass intArrCls = env->FindClass("Ljava/lang/String;")

 

   数组类型的描述符则为,则为:  [ +其类型的域描述符        (后文说明)

           例如:

                 int [ ]    其描述符为[I

                 float [ ]  其描述符为[F

                 String [ ]  其描述符为[Ljava/lang/String;

 

 域描述符

 

      1、基本类型的描述符已经被定义好了,如下表所示:

 

                          

 

 

     2、引用类型的描述符

 

         一般引用类型则为L +该类型类描述符 + ;   (注意,这儿的分号只得是JNI的一部分,而不是我们汉语中的分段,下同)

                例如:String类型的域描述符为 Ljava/lang/String;  

 

          对于数组,其为 :  [ + 其类型的域描述符 + ;

                 int[ ]    其描述符为[I

                 float[ ]  其描述符为[F

                 String[ ]  其描述符为[Ljava/lang/String;

                Object[ ]类型的域描述符为[Ljava/lang/Object;

 

          多维数组则是 n[ +该类型的域描述符 , N代表的是几维数组。例如:

             int [ ][ ]其描述符为[[I

              float[ ][ ] 其描述符为[[F

 

 方法描述符

 

       将参数类型的域描述符按照申明顺序放入一对括号中后跟返回值类型的域描述符,规则如下: (参数的域描述符的叠加)返回

  类型描述符。对于,没有返回值的,用V(表示void)表示。举例如下:

 

  Java层方法                                             JNI函数签名

   String test ( )                                            Ljava/lang/String;

   int f (int i, Object object)                          (ILjava/lang/Object;)I

   void set (byte[ ] bytes)                              ([B)V

   void set (byte[ ] bytes)                              (Ljava/util/Map;)

                                                  (Ljava/io/FileDescriptor;JJ)

                                                  (Landroid/os/Parcel)

                                                 (Ljava/lang/Object)

 

 

 

     在编程时,如果是利用javah工具的话,这些都不需要我们手动编写对应的类型转换,如果不能用javah工具,就只能手动的

  进行类型转换了。

 

 

  

  AndroidNDK开发(3)————JNI数据类型的详解

 

 

 

 

 

 

 

 

 

 

在掌握了JNI函数的使用和相关类型的映射后,以及知晓何利用javah工具生成对应的jni函数以及如何生成动态

    链接库 (windos下就是.dll库,Linux就是.so库了,不懂在Window下生成dll动态库的,具体流程可看我的这篇博客:

   AndroidJNI的使用之一:Java原生JNI的使用、javah指令的使用以及图解教材)。即可掌握JNI的使用了了。

 

        总的来说,JNI是不难的。通过前面的学习相信你应该有所了解。今天,我们从几个简单的小例子,来对JNI进行下实战训练。

     可都是些小例子,耐心看咯。

 

        主要操作内容,包括如下几个部分:

 

               1、在Native层返回一个字符串

               2、从Native层返回一个int型二维数组(int a[ ][ ]) 

               3、从Native层操作Java层的类:读取/设置类属性

               4、在Native层操作Java层的类:读取/设置类属性、回调Java方法 

               5、从Native层返回一个复杂对象(即一个类咯)

               6、在Java层传递复杂对象至Native

               7、从Native层返回Arraylist集合对象

 

      广而告知,这些操作就是简单的利用一些JNI函数即实现了。so easy

 

 一、在Native层返回一个字符串

       Java层原型方法:

[java] view plaincopyprint?

1.  public class HelloJni {  

2.      ...  

3.      public native void getAJNIString();  

4.      ...  

5.  }     



       Native层该方法实现为 :

[java] view plaincopyprint?

1.  /* 

2.   * Class:     com_feixun_jni_HelloJni 

3.   * Method:    getAJNIString 

4.   * Signature: ()Ljava/lang/String; 

5.   */   

6.  //返回字符串  

7.  JNIEXPORT jstring JNICALL Java_com_feixun_jni_HelloJni_getAJNIString(JNIEnv * env, jobject obj)  

8.  {  

9.      jstring str = env->newStringUTF("HelloJNI");  //直接使用该JNI构造一个jstring对象返回  

10.     return str ;  

11. }  



 

二、在Native层返回一个int型二维数组(inta[ ][ ])

    Java层原型方法:

[java] view plaincopyprint?

1.  public class HelloJni {  

2.      ...  

3.      //参数代表几行几列数组 ,形式如:int a[dimon][dimon]  

4.      private native int[][] getTwoArray(int dimon) ;   

5.      ...  

6.  }     


  
   Native层该方法实现为 :

[java] view plaincopyprint?

1.  /* 

2.   * Class:     com_feixun_jni_HelloJni 

3.   * Method:    getTwoArray 

4.   * Signature: (I)[[I 

5.   */  

6.  //通过构造一个数组的数组, 返回 一个二维数组的形式  

7.  JNIEXPORT jobjectArray JNICALL Java_com_feixun_jni_HelloJni_getTwoArray  

8.    (JNIEnv * env, jobject object, jint dimion)  

9.  {  

10.       

11.     jclass intArrayClass = env->FindClass("[I"); //获得一维数组 的类引用,即jintArray类型  

12.     //构造一个指向jintArray类一维数组的对象数组,该对象数组初始大小为dimion  

13.     jobjectArray obejctIntArray  =  env->NewObjectArray(dimion ,intArrayClass , NULL);  

14.   

15.     //构建dimion个一维数组,并且将其引用赋值给obejctIntArray对象数组  

16.     forint i = 0 ; i< dimion  ; i++ )  

17.     {  

18.         //构建jint型一维数组  

19.         jintArray intArray = env->NewIntArray(dimion);  

20.   

21.         jint temp[10]  ;  //初始化一个容器,假设 dimion  < 10 ;  

22.         forint j = 0 ; j < dimion ; j++)  

23.         {  

24.             temp[j] = i + j  ; //赋值  

25.         }  

26.           

27.         //设置jit型一维数组的值  

28.         env->SetIntArrayRegion(intArray, 0 , dimion ,temp);  

29.         //object对象数组赋值,即保持对jint一维数组的引用  

30.         env->SetObjectArrayElement(obejctIntArray , i ,intArray);  

31.   

32.         env->DeleteLocalRef(intArray);  //删除局部引用  

33.     }  

34.   

35.     return   obejctIntArray; //返回该对象数组  

36. }  




 三、在Native层操作Java层的类:读取/设置类属性

 

     Java层原型方法:

[java] view plaincopyprint?

1.  public class HelloJni {  

2.      ...  

3.      //Native层读取/设置属性值  

4.      public native void native_set_name() ;  

5.      ...  

6.        

7.      private String name = "I am at Java" ; //类属性  

8.  }     


    Native层该方法实现为 :

[java] view plaincopyprint?

1.  /* 

2.   * Class:     com_feixun_jni_HelloJni 

3.   * Method:    native_set_name 

4.   * Signature: ()V  

5.   */  

6.  //Native层操作Java对象,读取/设置属性等  

7.  JNIEXPORT void JNICALL Java_com_feixun_jni_HelloJni_native_1set_1name  

8.    (JNIEnv *env , jobject  obj )  //obj代表执行此JNI操作的类实例引用  

9.  {  

10.    //获得jfieldID 以及 该字段的初始值  

11.    jfieldID  nameFieldId ;  

12.   

13.    jclass cls = env->GetObjectClass(obj);  //获得Java层该对象实例的类引用,即HelloJNI类引用  

14.   

15.    nameFieldId = env->GetFieldID(cls , "name" , "Ljava/lang/String;"); //获得属性句柄  

16.   

17.    if(nameFieldId == NULL)  

18.    {  

19.        cout << 没有得到name 的句柄Id \n;" ;  

20.    }  

21.    jstring javaNameStr = (jstring)env->GetObjectField(obj ,nameFieldId);  // 获得该属性的值  

22.    const char * c_javaName = env->GetStringUTFChars(javaNameStr , NULL);  //转换为 char *类型  

23.    string str_name = c_javaName ;    

24.    cout << "the name from java is " << str_name << endl ; //输出显示  

25.    env->ReleaseStringUTFChars(javaNameStr , c_javaName);  //释放局部引用  

26.   

27.    //构造一个jString对象  

28.    char * c_ptr_name = "I come from Native" ;  

29.      

30.    jstring cName = env->NewStringUTF(c_ptr_name); //构造一个jstring对象  

31.   

32.    env->SetObjectField(obj , nameFieldId , cName); // 设置该字段的值  

33. }  



 

四、在Native层操作Java层的类:回调Java方法 

    Java层原型方法:

[java] view plaincopyprint?

1.  public class HelloJni {  

2.      ...  

3.      //Native层回调的方法实现  

4.      public void callback(String fromNative){       

5.          System.out.println(" I was invoked by native method  ############# " + fromNative);  

6.      };  

7.      public native void doCallBack(); //Native层会调用callback()方法  

8.      ...   

9.        

10.     // main函数  

11.     public static void main(String[] args)   

12.     {  

13.         new HelloJni().ddoCallBack();  

14.     }     

15. }     



    Native层该方法实现为 :

[java] view plaincopyprint?

1.  /* 

2.   * Class:     com_feixun_jni_HelloJni 

3.   * Method:    doCallBack 

4.   * Signature: ()V 

5.   */  

6.  //Native层回调Java类方法  

7.  JNIEXPORT void JNICALL Java_com_feixun_jni_HelloJni_doCallBack  

8.    (JNIEnv * env , jobject obj)  

9.  {  

10.      //回调Java中的方法  

11.   

12.     jclass cls = env->GetObjectClass(obj);//获得Java类实例  

13.     jmethodID callbackID = env->GetMethodID(cls , "callback" , "(Ljava/lang/String;)V") ;//或得该回调方法句柄  

14.   

15.     if(callbackID == NULL)  

16.     {  

17.          cout << "getMethodId is failed \n" << endl ;  

18.     }  

19.     

20.     jstring native_desc = env->NewStringUTF(" I am Native");  

21.   

22.     env->CallVoidMethod(obj , callbackID , native_desc); //回调该方法,并且传递参数值  

23. }  

 

    接下来,我们会操作复杂对象,也就是Java层的类,包括从Native层返回一个类以及传递一个类到Native层去,这儿我们

使用的类非常简单,如下:

     Student.java

[java] view plaincopyprint?

1.  package com.feixun.jni;  

2.    

3.  public class Student  

4.  {  

5.      private int age ;  

6.      private String name ;  

7.      //构造函数,什么都不做  

8.      public Student(){ }  

9.        

10.     public Student(int age ,String name){  

11.         this.age = age ;  

12.         this.name = name ;  

13.     }  

14.       

15.     public int getAge() {  

16.         return age;  

17.     }  

18.     public void setAge(int age) {  

19.         this.age = age;  

20.     }  

21.     public String getName() {  

22.         return name;  

23.     }  

24.     public void setName(String name){  

25.         this.name = name;  

26.     }  

27.       

28.     public String toString(){  

29.         return "name --- >" + name + "  age --->" + age ;  

30.     }  

31. }  



 五、在Native层返回一个复杂对象(即一个类咯)

 

     Java层的方法对应为:

[java] view plaincopyprint?

1.  public class HelloJni {  

2.      ...  

3.      //Native层返回一个Student对象  

4.      public native Student nativeGetStudentInfo() ;  

5.      ...   

6.  }     


     Native层该方法实现为:       

[java] view plaincopyprint?

1.  /* 

2.   * Class:     com_feixun_jni_HelloJni 

3.   * Method:    nativeGetStudentInfo 

4.   * Signature: ()Lcom/feixun/jni/Student; 

5.   */  

6.  //返回一个复杂对象  

7.  JNIEXPORT jobject JNICALL Java_com_feixun_jni_HelloJni_nativeGetStudentInfo  

8.    (JNIEnv * env, jobject obl)  

9.  {  

10.     //关于包描述符,这儿可以是 com/feixun/jni/Student 或者是 Lcom/feixun/jni/Student;   

11.     //   这两种类型 都可以获得class引用  

12.     jclass stucls = env->FindClass("com/feixun/jni/Student"); //或得Student类引用  

13.   

14.     //获得得该类型的构造函数  函数名为 <init> 返回类型必须为 void  V  

15.     jmethodID constrocMID = env->GetMethodID(stucls,"<init>","(ILjava/lang/String;)V");  

16.   

17.     jstring str = env->NewStringUTF(" come from Native ");  

18.   

19.     jobject stu_ojb = env->NewObject(stucls,constrocMID,11,str);  //构造一个对象,调用该类的构造函数,并且传递参数  

20.   

21.   

22.     return stu_ojb ;  

23. }  

 

 六、从Java层传递复杂对象至Native

 

     Java层的方法对应为:

[java] view plaincopyprint?

1.  public class HelloJni {  

2.      ...  

3.      //Native层打印Student的信息  

4.      public native void  printStuInfoAtNative(Student stu);  

5.      ...   

6.  }  



     Native层该方法实现为 :      

[java] view plaincopyprint?

1.  /* 

2.   * Class:     com_feixun_jni_HelloJni 

3.   * Method:    printStuInfoAtNative 

4.   * Signature: (Lcom/feixun/jni/Student;)V 

5.   */  

6.  //Native层输出Student的信息  

7.  JNIEXPORT void JNICALL Java_com_feixun_jni_HelloJni_printStuInfoAtNative  

8.    (JNIEnv * env, jobject obj,  jobject obj_stu) //第二个类实例引用代表Student类,即我们传递下来的对象  

9.  {  

10.       

11.     jclass stu_cls = env->GetObjectClass(obj_stu); //或得Student类引用  

12.   

13.     if(stu_cls == NULL)  

14.     {  

15.         cout << "GetObjectClass failed \n" ;  

16.     }  

17.     //下面这些函数操作,我们都见过的。O(_)O~  

18.     jfieldID ageFieldID = env->GetFieldID(stucls,"age","I"); //获得得Student类的属性id   

19.     jfieldID nameFieldID = env->GetFieldID(stucls,"name","Ljava/lang/String;"); // 获得属性ID  

20.   

21.     jint age = env->GetIntField(objstu , ageFieldID);  //获得属性值  

22.     jstring name = (jstring)env->GetObjectField(objstu , nameFieldID);//获得属性值  

23.   

24.     const char * c_name = env->GetStringUTFChars(name ,NULL);//转换成 char *  

25.    

26.     string str_name = c_name ;   

27.     env->ReleaseStringUTFChars(name,c_name); //释放引用  

28.       

29.     cout << " at Native age is :" << age << " # name is " << str_name << endl ;   

30. }  




 七、最后加个难度,即在Native层返回集合对象(留这儿,以后也好找点)

 

     Java层的对应方法为:

[java] view plaincopyprint?

1.  public class HelloJni {  

2.      ...  

3.      //Native层返回ArrayList集合   

4.      public native ArrayList<Student> native_getListStudents();  

5.      ...   

6.  }     


     Native层该方法实现为:       

[java] view plaincopyprint?

1.  /* 

2.   * Class:     com_feixun_jni_HelloJni 

3.   * Method:    native_getListStudents 

4.   * Signature: ()Ljava/util/ArrayList; 

5.   */ //获得集合类型的数组  

6.  JNIEXPORT jobject JNICALL Java_com_feixun_jni_HelloJni_native_getListStudents  

7.    (JNIEnv * env, jobject obj)  

8.  {  

9.      jclass list_cls = env->FindClass("Ljava/util/ArrayList;");//获得ArrayList类引用  

10.   

11.     if(listcls == NULL)  

12.     {  

13.         cout << "listcls is null \n" ;  

14.     }  

15.     jmethodID list_costruct = env->GetMethodID(list_cls , "<init>","()V"); //获得得构造函数Id  

16.   

17.     jobject list_obj = env->NewObject(list_cls , list_costruct); //创建一个Arraylist集合对象  

18.     //或得Arraylist类中的 add()方法ID,其方法原型为: boolean add(Object object) ;  

19.     jmethodID list_add  = env->GetMethodID(list_cls,"add","(Ljava/lang/Object;)Z");   

20.     

21.     jclass stu_cls = env->FindClass("Lcom/feixun/jni/Student;");//获得Student类引用  

22.     //获得该类型的构造函数  函数名为 <init> 返回类型必须为 void  V  

23.     jmethodID stu_costruct = env->GetMethodID(stu_cls , "<init>""(ILjava/lang/String;)V");  

24.   

25.     for(int i = 0 ; i < 3 ; i++)  

26.     {  

27.         jstring str = env->NewStringUTF("Native");  

28.         //通过调用该对象的构造函数来new 一个 Student实例  

29.         jobject stu_obj = env->NewObject(stucls , stu_costruct , 10,str);  //构造一个对象  

30.           

31.         env->CallBooleanMethod(list_obj , list_add , stu_obj); //执行Arraylist类实例的add方法,添加一个stu对象  

32.     }  

33.   

34.     return list_obj ;  

35. }  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0 0