JNI知識(七)C++/C接口是指針的情況

有時候我們的C++/C帶代碼是現成的,需要向上用JNI封裝,然後用Java調用。Java中是沒有指針的,但是Java通過JNI調用C++/C接口,C++/C是有指針的,這種情況Java該作何處理。

  1. C++/C指針作爲輸出參數

  這種在前面出參爲String類型的情況最後更爲一般的情況已經提到過。這裏在展開來討論。

  • 基本類型

     example:

     Java接口:

     public void getAge(int age[]);

     JNI:

     JNIEXPORT void JNICALL Java_setAge_ 1native (JNIEnv *env, jclass thiz,

                                                  jintArray age)

    {      

        int age;

        getAge(&age); // setAge爲更下層的函數接口

        jint  as32AgeArray[1];

        s32AgeArray [0] = age;

       

        /* 這個操作實際有些像memcpy,如果數組大小比較大,並且拷貝若干

            個連續的元素,就修改上面方法的第2,3個參數即可

        */

       env->SetIntArrayRegion(age, 0, 1, (jint *) as32AgeArray);

                                    }

  • 輸出參數類型是class

    /* C++/C中 struct */

  typedef struct _Para_tag

  {

       int x;

       short y;

       char az[100];

       char h;

       unsigned int t;

   }Para_Tag;


   對應的Java中的class爲:

   public class Para_Tag

   {

       int m_x;

       short m_y;

       String m_z;

       char m_h;

       long m_t;

       public Para_tag(int x,short y,String z,char h,long t)

      {

           m_x = x;

           m_y = y;

           m_z = z;

           m_h = h;

           m_t = t;

       }

   }

   

  Java 接口:

  public  void getPara(Para_Tag tag);


   JNI:


  JNIEXPORT void  JNICALL Java_getPara_ 1native (JNIEnv *env, jclass thiz, jobject obj)

  {

       Para_Tag  tag;


       getPara(&tag);// 取得C++/C中Para_Tag結構體的值

       // 給java的Para_Tag class賦值

       jclass DataCls = env->FindClass("com/Para_Tag"); // 通過class path找到class的標識


       /*  對class中的每個變量逐一賦值 */

       jfieldID dataId = env->GetFieldID(DataCls, "m_x", "I");  

       env->SetIntField(obj, dataId,tag.x);

       dataId = env->GetFieldID(DataCls, "m_y", "S");

       env->SetShortField(obj, dataId,tag.y);

       /*  注意C++中的char * 類型如何通過JNI轉換爲Java的String  */

       dataId = env->GetFieldID(DataCls, "m_z", "Ljava/lang/String;");        

       jstring strTmp = env->NewStringUTF((char *)tag.az);

       env->SetObjectField(objdata, dataId, strTmp);

       dataId = env->GetFieldID(DataCls, "m_h", "C");

       env->SetCharField(obj, dataId,tag.h);

       dataId = env->GetFieldID(DataCls, "m_t", "J"); // 注意long對應的簽名是J,不是L

       env->SetLongField(obj, dataId,tag.t);

   }

   上面這種做法是ok的,但是效率太低,每調用一次vmenv函數就會和虛擬機交互一次,,和虛擬機交互次數太多,有沒有什麼辦法提高效率。

   有,那就是如果對class中的多個成員變量都要賦值的話可以調用java的構造函數賦值,這樣不管有多少個函數,只會和虛擬機交互一次,會大大提高效率。

   修改後用構造函數賦值的例子如下:

        JNIEXPORT void  JNICALL Java_getPara_ 1native (JNIEnv *env, jclass thiz, jobject obj)

       {

            Para_Tag  tag;

     getPara(&tag);// 取得C++/CPara_Tag結構體的值

     jclass DataCls = env->FindClass("com/Para_Tag"); // 通過class path找到class的標

           jmethodID RtnInitId = env->GetMethodID(DataCls, "<init>", "(ISLjava/lang/String;CJ)V");

           jstring strTmp = env->NewStringUTF((char *)tag.az);

           env->CallVoidMethod(obj, RtnInitId, tag.x, tag.y,strTmp,tag.h,tag.t);

       }

   這裏用到了C++/C中調用Java中的構造函數,實際上C++/C中還可以調用Java中的其它函數,後面會提到。

2. C++/C指針作爲輸入參數

   這種情況下就要具體問題,具體分析了。

   如果C++/C代碼需要的僅僅是一個地址,且C++/C不會回傳給值給Java,那麼Java就傳遞一個int型的數即可。

   例如:

           C++/C:    void setValue(int  *ps32Addr,int value);

   僅僅是給一個地址寫值,那麼

    Java:public void setValue(int s32Addr,int value);

         JNI:

        JNIEXPORT void  JNICALL Java_setValue_ 1native (JNIEnv *env, jclass thiz, jint s32Addr,jint value)

       {

             int *ps32Addr = (int *)s32Addr;

           setValue(ps32Addr,value);

      }

 

如果C++/C的指針含有從Java中傳遞的數據信息,就需做如下處理:

typedef struct _Para_tag

{

   int x;

   short y;

   char az[100];

   char h;

}Para_Tag;

C++/C : void setPara(Para_Tag *pstTag)

Java:

public class Para_Tag

{

   int x;

   short y;

   String z;

   char h;

   long t;    

}

public void setPara(Para_Tag   tag);

JNI:

JNIEXPORT void  JNICALL Java_setPara_ 1native (JNIEnv *env, jclass thiz, jobject obj)

{

   Para_Tag  tag;


jclass DataCls = env->FindClass("com/Para_Tag");

jfieldID dataId = env->GetFieldID(DataCls, "x", "I");

tag.x = env->GetIntField(obj, dataId);


dataId = env->GetFieldID(DataCls, "y", "S");

tag.y = env->GetShortField(obj, dataId);


dataId = env->GetFieldID(DataCls, "z", "Ljava/lang/String;");

jstring jstr = (jstring)env->GetObjectField(obj, dataId);

const char* str;

   jboolean isCopye = false;

   if(NULL != jstr)

   {

       str = env->GetStringUTFChars(jstr, &isCopye);

   }

   if(str == NULL)

   {

       return;                  

   }

   strncpy(tag.az,str,100);

   tag.az[99] = '\0';    

   dataId = env->GetFieldID(DataCls, "h", "C");

tag.h = env->GetCharField(obj, dataId);

dataId = env->GetFieldID(DataCls, "t", "J");

tag.t = (jlong)env->GetLongField(obj, dataId);

               setPara(&tag);

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章