Jni接口-深入研究參數的傳遞(一)


  在上一個隨筆中介紹了怎樣實現一個簡單的Jni小程序。在這一篇里主要是說一下JAVA與C++之間的參數傳遞問題。

  本人是個Java程序員,工作沒幾年  菜鳥級別,C++不是很熟悉,但對.NET到是了解一些,所以這里面的C++部分都用C++.net來講的。為了便於理解,文檔中可能會有很多通俗易懂的白話,最近也是項目中用到了Jni 才學習了幾天,所以這里要是有哪說得不對,還請大家見諒,發現問題就指出來,大家一起學習 哈!

  先大致回顧下上一篇的內容,在上一篇里我們創建了一個JAVA類Test.java和C++.net的Jin01項目。主要是實現Jin01中輸出“第一個Jni小程序”,然后用Test.java來調用。(詳情請見上一篇內容)
  Jni01中的函數是:

  #include "stdafx.h"

  #include "WINSCARD.H"

  #include "com_test01_Test.h"

  using namespace System;

  int main(array<System::String ^> ^args) {  

    Console::WriteLine(L"Hello World");  

    return 0;

  }

  //實現Java_com_test01_Test_firstTest方法

  JNIEXPORT void JNICALL Java_com_test01_Test_firstTest(JNIEnv *, jobject){

    Console::WriteLine(L"第一個Jni小程序");

  }

  Test.java代碼如下:

  public class Test {  

    public native void firstTest();//

      public static void main(String[] args) {   

      System.loadLibrary("Jni01");   

      Test t=new Test();

       t.firstTest();  

    }

  }

    1、com_test01_Test.h頭文件中實現Jni接口方法深入研究

  在上一篇的例子中實現Jni接口的方法聲明在com_test01_Test.h頭文件中,代碼如下:(以下按照字體顏色來解釋每個部分的意思)

  JNIEXPORT void JNICALL Java_com_test01_Test_firstTest   (JNIEnv * env, jobject obj);

  (1)JNIEXPORT :在Jni編程中所有本地語言實現Jni接口的方法前面都有一個"JNIEXPORT",這個可以看做是Jni的一個標志,至今為止沒發現它有什么特殊的用處。

  (2)void :這個學過編程的人都知道,當然是方法的返回值了。

  (3)JNICALL :這個可以理解為Jni 和Call兩個部分,和起來的意思就是 Jni調用XXX(后面的XXX就是JAVA的方法名)。

  (4)Java_com_test01_Test_firstTest:這個就是被上一步中被調用的部分,也就是Java中的native 方法名,這里起名字的方式比較特別,是:包名+類名+方法名。

  (5)JNIEnv * env:這個env可以看做是Jni接口本身的一個對象,在上一篇中提到的jni.h頭文件中存在着大量被封裝好的函數,這些函數也是Jni編程中經常被使用到的,要想調用這些函數就需要使用JNIEnv這個對象。例如:env->GetObjectClass()。(詳情請查看jni.h)

  (6)jobject obj:剛才在Test類的main方法中有這樣一段代碼: 

           Test t=new Test(); t.firstTest();

             這個jobject需要兩種情況分析。上段代碼中firstTest方法是一個非靜態方法,在Java中要想調用它必須先實例化對象,然后再用對象調用它,那這個時候jobject就可以看做Java類的一個實例化對象,也就是obj就是t。如果firstTest是一個靜態方法,那么在Java中,它不是屬於一個對象的,而是屬於一個類的,Java中用Test.firstTest()這樣的方式來調用,這個時候jobject就可以看做是java類的本身,也就是obj就是Test.class。

  2、Jni中的數據類型

  每一個Java的數據類型在Jni中都一個和它相對應的數據庫類型,這樣才能保證Java調用C或者C++的過程中數據的正確性。

  打開Jni.h文件,有如下代碼:

  

   這里聲明了所有Jni支持的數據類型,可以發現一個規律所有Jni的數據類型前面都有一個”J“字母,這樣主要是為了好記。在Java中所有的對象都以引用的形式體現的,為了保持一致 所以在C與C++中使用了指針類型。Java與Jni中數據類型的對照表如下:

  

  3、實例:在C++.net程序中改變Java中變量的值

  在原有Test.java中聲明一個整形變量message,如下:

  public class Test {  

    public native void firstTest();//第一個Jni  

    public int message;  

    public static void main(String[] args) {   

      System.loadLibrary("Jni01");   

      new Test().firstTest();  

    }

  }

  在Jni01的 Java_com_test01_Test_firstTest方法中寫如下代碼:

  JNIEXPORT void JNICALL Java_com_test01_Test_firstTest(JNIEnv * env, jobject obj){

     jclass class_Test=env->GetObjectClass(obj);    //注釋(1)

     jfieldID fid_msg=env->GetFieldID(class_Test,"message","I");//注釋(2)

     env->SetIntField(obj,fid_msg,123);//注釋(3)

  }

  (1)調用GetObjectClass方法來獲取Jclass,GetObjectClass的參數就是obj

  (2)調用GetFieldID方法來獲取jfieldID,這里要說明一下Jni的所有操作,其實就是操作方法或者是操作屬性兩種。操作方法時需要根據方法的ID(jmethodID)來操作,可以理解為jmethodID標識了這個方法,也就是通過這個jmethodID可以找到你要找的方法。同理操作屬性時也要根據該屬性的ID(jfieldID )來操作。上面那段代碼里我們要改變 變量message的值,所以要先獲取該變量的jfieldID 。獲取變量的jfieldID 方法是GetFieldID。GetFieldID需要3個參數。第一個是上一步獲取的Jclass,第二個參數是Java中的變量名,最后一個參數是變量簽名(int 的變量簽名是”I“)。

    下面是所有Jni中的變量簽名列表:

   

  (3)最后調用SetIntField方法就可以設置變量 message的值了。在JAVA的測試環境中打印一下變量的值就知道是否成功了。

  全部完成后,可以自己試驗下使用GetIntField方法將message的值取出來。對於這些Jni.h中的方法就不過多的說了,自己看就應該能會用。在以后的隨筆里會多說一些數據轉換的問題。

 

  

  

 

  

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM