<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    悟心

    成功不是將來才有的,而是從決定去做的那一刻起,持續累積而成。 上人生的旅途罷。前途很遠,也很暗。然而不要怕。不怕的人的面前才有路。

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      93 隨筆 :: 1 文章 :: 103 評論 :: 0 Trackbacks
    本文為在   32   位   Windows   平臺上實現   Java   本地方法提供了實用的示例、步驟和準則。這些示例包括傳遞和返回常用的數據類型。  
      本文中的示例使用   Sun   Microsystems   公司創建的   Java   Development   Kit   (JDK)   版本   1.1.6   和   Java   本地接口   (JNI)   規范。用   C   語言編寫的本地代碼是用   Microsoft   Visual   C++   編譯器編譯生成的。  
      簡介  
      本文提供調用本地   C   代碼的   Java   代碼示例,包括傳遞和返回某些常用的數據類型。本地方法包含在特定于平臺的可執行文件中。就本文中的示例而言,本地方法包含在   Windows   32   位動態鏈接庫   (DLL)   中。  
      不過我要提醒您,對   Java   外部的調用通常不能移植到其他平臺上,在   applet   中還可能引發安全異常。實現本地代碼將使您的   Java   應用程序無法通過   100%   純   Java   測試。但是,如果必須執行本地調用,則要考慮幾個準則:  
      1. 將您的所有本地方法都封裝在單個類中,這個類調用單個   DLL。對于每種目標操作系統,都可以用特定于適當平臺的版本替換這個   DLL。這樣就可以將本地代碼的影響減至最小,并有助于將以后所需的移植問題包含在內。    
      2. 本地方法要簡單。盡量將您的   DLL   對任何第三方(包括   Microsoft)運行時   DLL   的依賴減到最小。使您的本地方法盡量獨立,以將加載您的   DLL   和應用程序所需的開銷減到最小。如果需要運行時   DLL,必須隨應用程序一起提供它們。    
      Java   調用   C  
      對于調用   C   函數的   Java   方法,必須在   Java   類中聲明一個本地方法。在本部分的所有示例中,我們將創建一個名為   MyNative   的類,并逐步在其中加入新的功能。這強調了一種思想,即將本地方法集中在單個類中,以便將以后所需的移植工作減到最少。  
      示例   1   --   傳遞參數    
      在第一個示例中,我們將三個常用參數類型傳遞給本地函數:String、int   和   boolean。本例說明在本地   C   代碼中如何引用這些參數。  
         
      public   class   MyNative  
      {  
          public   void   showParms(   String   s,   int   i,   boolean   b   )  
          {  
              showParms0(   s,   i   ,   b   );  
          }  
       
          private   native   void   showParms0(   String   s,   int   i,   boolean   b   );  
       
          static  
          {  
              System.loadLibrary(   "MyNative"   );  
          }  
      }  
      請注意,本地方法被聲明為專用的,并創建了一個包裝方法用于公用目的。這進一步將本地方法同代碼的其余部分隔離開來,從而允許針對所需的平臺對它進行優化。static   子句加載包含本地方法實現的   DLL。  
      下一步是生成   C   代碼來實現   showParms0   方法。此方法的   C   函數原型是通過對   .class   文件使用   javah   實用程序來創建的,而   .class   文件是通過編譯   MyNative.java   文件生成的。這個實用程序可在   JDK   中找到。下面是   javah   的用法:  
        javac   MyNative.java(將   .java   編譯為   .class)  
        javah   -jni    
                  MyNative(生成   .h   文件)  
      這將生成一個   MyNative.h   文件,其中包含一個本地方法原型,如下所示:  
         
      /*  
        *   Class:           MyNative  
        *   Method:         showParms0  
        *   Signature:   (Ljava/lang/String;IZ)V  
        */  
      JNIEXPORT   void   JNICALL   Java_MyNative_showParms0  
          (JNIEnv   *,   jobject,   jstring,   jint,   jboolean);  
      第一個參數是調用   JNI   方法時使用的   JNI   Environment   指針。第二個參數是指向在此   Java   代碼中實例化的   Java   對象   MyNative   的一個句柄。其他參數是方法本身的參數。請注意,MyNative.h   包括頭文件   jni.h。jni.h   包含   JNI   API   和變量類型(包括jobject、jstring、jint、jboolean,等等)的原型和其他聲明。  
      本地方法是在文件   MyNative.c   中用   C   語言實現的:  
         
      #include   <stdio.h>  
      #include   "MyNative.h"  
      JNIEXPORT   void   JNICALL   Java_MyNative_showParms0  
          (JNIEnv   *env,   jobject   obj,   jstring   s,   jint   i,   jboolean   b)  
      {  
          const   char*   szStr   =   (*env)->GetStringUTFChars(   env,   s,   0   );  
          printf(   "String   =   [%s]\n",   szStr   );  
          printf(   "int   =   %d\n",   i   );  
          printf(   "boolean   =   %s\n",   (b==JNI_TRUE   ?   "true"   :   "false")   );  
          (*env)->ReleaseStringUTFChars(   env,   s,   szStr   );  
      }  
      JNI   API,GetStringUTFChars,用來根據   Java   字符串或   jstring   參數創建   C   字符串。這是必需的,因為在本地代碼中不能直接讀取   Java   字符串,而必須將其轉換為   C   字符串或   Unicode。有關轉換   Java   字符串的詳細信息,請參閱標題為   NLS   Strings   and   JNI   的一篇論文。但是,jboolean   和   jint   值可以直接使用。  
      MyNative.dll   是通過編譯   C   源文件創建的。下面的編譯語句使用   Microsoft   Visual   C++   編譯器:  
        cl   -Ic:\jdk1.1.6\include   -Ic:\jdk1.1.6\include\win32   -LD   MyNative.c    
                  -FeMyNative.dll    
      其中   c:\jdk1.1.6   是   JDK   的安裝路徑。  
      MyNative.dll   已創建好,現在就可將其用于   MyNative   類了。可以這樣測試這個本地方法:在   MyNative   類中創建一個   main   方法來調用   showParms   方法,如下所示:  
         
            public   static   void   main(   String[]   args   )  
            {  
                MyNative   obj   =   new   MyNative();  
                obj.showParms(   "Hello",   23,   true   );  
                obj.showParms(   "World",   34,   false   );  
            }  
      當運行這個   Java   應用程序時,請確保   MyNative.dll   位于   Windows   的   PATH   環境變量所指定的路徑中或當前目錄下。當執行此   Java   程序時,如果未找到這個   DLL,您可能會看到以下的消息:  
        java   MyNative    
        Can't   find   class   MyNative    
      這是因為   static   子句無法加載這個   DLL,所以在初始化   MyNative   類時引發異常。Java   解釋器處理這個異常,并報告一個一般錯誤,指出找不到這個類。如果用   -verbose   命令行選項運行解釋器,您將看到它因找不到這個   DLL   而加載   UnsatisfiedLinkError   異常。  
      如果此   Java   程序完成運行,就會輸出以下內容:  
        java   MyNative    
        String   =   [Hello]    
        int   =   23    
                   
        boolean   =   true    
        String   =   [World]    
        int    
                  =   34    
        boolean   =   false    
      示例   2   --   返回一個值    
      本例將說明如何在本地方法中實現返回代碼。將這個方法添加到   MyNative   類中,這個類現在變為以下形式:  
         
      public   class   MyNative  
      {  
          public   void   showParms(   String   s,   int   i,   boolean   b   )  
          {  
              showParms0(   s,   i   ,   b   );  
          }  
          public   int   hypotenuse(   int   a,   int   b   )  
          {  
              return   hyptenuse0(   a,   b   );  
          }  
       
          private   native   void   showParms0(   String   s,   int   i,   boolean   b   );  
          private   native   int     hypotenuse0(   int   a,   int   b   );  
       
          static  
          {  
              System.loadLibrary(   "MyNative"   );  
          }  
       
          /*   測試本地方法   */  
          public   static   void   main(   String[]   args   )  
          {  
              MyNative   obj   =   new   MyNative();  
              System.out.println(   obj.hypotenuse(3,4)   );  
              System.out.println(   obj.hypotenuse(9,12)   );  
          }  
      }  
      公用的   hypotenuse   方法調用本地方法   hypotenuse0   來根據傳遞的參數計算值,并將結果作為一個整數返回。這個新本地方法的原型是使用   javah   生成的。請注意,每次運行這個實用程序時,它將自動覆蓋當前目錄中的   MyNative.h。按以下方式執行   javah:  
        javah   -jni   MyNative    
      生成的   MyNative.h   現在包含   hypotenuse0   原型,如下所示:  
         
      /*  
        *   Class:           MyNative  
        *   Method:         hypotenuse0  
        *   Signature:   (II)I  
        */  
      JNIEXPORT   jint   JNICALL   Java_MyNative_hypotenuse0  
          (JNIEnv   *,   jobject,   jint,   jint);  
      該方法是在   MyNative.c   源文件中實現的,如下所示:  
         
      #include   <stdio.h>  
      #include   <math.h>  
      #include   "MyNative.h"  
       
      JNIEXPORT   void   JNICALL   Java_MyNative_showParms0  
          (JNIEnv   *env,   jobject   obj,   jstring   s,   jint   i,   jboolean   b)  
      {  
          const   char*   szStr   =   (*env)->GetStringUTFChars(   env,   s,   0   );  
          printf(   "String   =   [%s]\n",   szStr   );  
          printf(   "int   =   %d\n",   i   );  
          printf(   "boolean   =   %s\n",   (b==JNI_TRUE   ?   "true"   :   "false")   );  
          (*env)->ReleaseStringUTFChars(   env,   s,   szStr   );  
      }  
       
      JNIEXPORT   jint   JNICALL   Java_MyNative_hypotenuse0  
          (JNIEnv   *env,   jobject   obj,   jint   a,   jint   b)  
      {  
          int   rtn   =   (int)sqrt(   (double)(   (a*a)   +   (b*b)   )   );  
          return   (jint)rtn;  
      }  
      再次請注意,jint   和   int   值是可互換的。使用相同的編譯語句重新編譯這個   DLL:  
        cl   -Ic:\jdk1.1.6\include   -Ic:\jdk1.1.6\include\win32   -LD   MyNative.c    
                  -FeMyNative.dll    
      現在執行   java   MyNative   將輸出   5   和   15   作為斜邊的值。  
      示例   3   --   靜態方法    
      您可能在上面的示例中已經注意到,實例化的   MyNative   對象是沒必要的。實用方法通常不需要實際的對象,通常都將它們創建為靜態方法。本例說明如何用一個靜態方法實現上面的示例。更改   MyNative.java   中的方法簽名,以使它們成為靜態方法:  
         
          public   static   int   hypotenuse(   int   a,   int   b   )  
          {  
              return   hypotenuse0(a,b);  
          }  
          ...  
          private   static   native   int     hypotenuse0(   int   a,   int   b   );  
      現在運行   javah   為   hypotenuse0   創建一個新原型,生成的原型如下所示:  
         
      /*  
        *   Class:           MyNative  
        *   Method:         hypotenuse0  
        *   Signature:   (II)I  
        */  
      JNIEXPORT   jint   JNICALL   Java_MyNative_hypotenuse0  
          (JNIEnv   *,   jclass,   jint,   jint);  
      C   源代碼中的方法簽名變了,但代碼還保持原樣:  
         
      JNIEXPORT   jint   JNICALL   Java_MyNative_hypotenuse0  
          (JNIEnv   *env,   jclass   cls,   jint   a,   jint   b)  
      {  
          int   rtn   =   (int)sqrt(   (double)(   (a*a)   +   (b*b)   )   );  
          return   (jint)rtn;  
      }  
      本質上,jobject   參數已變為   jclass   參數。此參數是指向   MyNative.class   的一個句柄。main   方法可更改為以下形式:  
         
          public   static   void   main(   String[]   args   )  
          {  
              System.out.println(   MyNative.hypotenuse(   3,   4   )   );  
              System.out.println(   MyNative.hypotenuse(   9,   12   )   );  
          }  
       
      因為方法是靜態的,所以調用它不需要實例化   MyNative   對象。本文后面的示例將使用靜態方法。  
      示例   4   --   傳遞數組    
      本例說明如何傳遞數組型參數。本例使用一個基本類型,boolean,并將更改數組元素。下一個示例將訪問   String(非基本類型)數組。將下面的方法添加到   MyNative.java   源代碼中:  
         
          public   static   void   setArray(   boolean[]   ba   )  
          {  
              for(   int   i=0;   i   <   ba.length;   i++   )  
                  ba[i]   =   true;  
              setArray0(   ba   );  
          }  
          ...  
          private   static   native   void   setArray0(   boolean[]   ba   );  
      在本例中,布爾型數組被初始化為   true,本地方法將把特定的元素設置為   false。同時,在   Java   源代碼中,我們可以更改   main   以使其包含測試代碼:  
         
              boolean[]   ba   =   new   boolean[5];  
              MyNative.setArray(   ba   );  
              for(   int   i=0;   i   <   ba.length;   i++   )  
                  System.out.println(   ba[i]   );  
      在編譯源代碼并執行   javah   以后,MyNative.h   頭文件包含以下的原型:  
         
      /*  
        *   Class:           MyNative  
        *   Method:         setArray0  
        *   Signature:   ([Z)V  
        */  
      JNIEXPORT   void   JNICALL   Java_MyNative_setArray0  
          (JNIEnv   *,   jclass,   jbooleanArray);  
      請注意,布爾型數組是作為單個名為   jbooleanArray   的類型創建的。基本類型有它們自已的數組類型,如   jintArray   和   jcharArray。非基本類型的數組使用   jobjectArray   類型。下一個示例中包括一個   jobjectArray。這個布爾數組的數組元素是通過   JNI   方法   GetBooleanArrayElements   來訪問的。針對每種基本類型都有等價的方法。這個本地方法是如下實現的:  
         
      JNIEXPORT   void   JNICALL   Java_MyNative_setArray0  
          (JNIEnv   *env,   jclass   cls,   jbooleanArray   ba)  
      {  
          jboolean*   pba   =   (*env)->GetBooleanArrayElements(   env,   ba,   0   );  
          jsize   len   =   (*env)->GetArrayLength(env,   ba);  
          int   i=0;  
          //   更改偶數數組元素  
          for(   i=0;   i   <   len;   i+=2   )  
              pba[i]   =   JNI_FALSE;  
          (*env)->ReleaseBooleanArrayElements(   env,   ba,   pba,   0   );  
      }  
      指向布爾型數組的指針可以使用   GetBooleanArrayElements   獲得。數組大小可以用   GetArrayLength   方法獲得。使用   ReleaseBooleanArrayElements   方法釋放數組。現在就可以讀取和修改數組元素的值了。jsize   聲明等價于   jint(要查看它的定義,請參閱   JDK   的   include   目錄下的   jni.h   頭文件)。  
      示例   5   --   傳遞   Java   String   數組    
      本例將通過最常用的非基本類型,Java   String,說明如何訪問非基本對象的數組。字符串數組被傳遞給本地方法,而本地方法只是將它們顯示到控制臺上。   MyNative   類定義中添加了以下幾個方法:  
         
          public   static   void   showStrings(   String[]   sa   )  
          {  
              showStrings0(   sa   );  
          }  
          private   static   void   showStrings0(   String[]   sa   );  
      并在   main   方法中添加了兩行進行測試:  
         
          String[]   sa   =   new   String[]   {   "Hello,",   "world!",   "JNI",   "is",   "fun."   };  
          MyNative.showStrings(   sa   );  
      本地方法分別訪問每個元素,其實現如下所示。  
         
      JNIEXPORT   void   JNICALL   Java_MyNative_showStrings0  
          (JNIEnv   *env,   jclass   cls,   jobjectArray   sa)  
      {  
          int   len   =   (*env)->GetArrayLength(   env,   sa   );  
          int   i=0;  
          for(   i=0;   i   <   len;   i++   )  
          {  
              jobject   obj   =   (*env)->GetObjectArrayElement(env,   sa,   i);  
              jstring   str   =   (jstring)obj;  
              const   char*   szStr   =   (*env)->GetStringUTFChars(   env,   str,   0   );  
              printf(   "%s   ",   szStr   );  
              (*env)->ReleaseStringUTFChars(   env,   str,   szStr   );  
          }  
          printf(   "\n"   );  
      }  
      數組元素可以通過   GetObjectArrayElement   訪問。在本例中,我們知道返回值是   jstring   類型,所以可以安全地將它從   jobject   類型轉換為   jstring   類型。字符串是通過前面討論過的方法打印的。有關在   Windows   中處理   Java   字符串的信息,請參閱標題為   NLS   Strings   and   JNI   的一篇論文。  
      示例   6   --   返回   Java   String   數組    
      最后一個示例說明如何在本地代碼中創建一個字符串數組并將它返回給   Java   調用者。MyNative.java   中添加了以下幾個方法:  
         
          public   static   String[]   getStrings()  
          {  
              return   getStrings0();  
          }  
          private   static   native   String[]   getStrings0();  
      更改   main   以使   showStrings   將   getStrings   的輸出顯示出來:  
         
          MyNative.showStrings(   MyNative.getStrings()   );  
      實現的本地方法返回五個字符串。  
         
      JNIEXPORT   jobjectArray   JNICALL   Java_MyNative_getStrings0  
          (JNIEnv   *env,   jclass   cls)  
      {  
          jstring             str;  
          jobjectArray   args   =   0;  
          jsize                 len   =   5;  
          char*                 sa[]   =   {   "Hello,",   "world!",   "JNI",   "is",   "fun"   };  
          int                     i=0;  
          args   =   (*env)->NewObjectArray(env,   len,   (*env)->FindClass(env,   "java/lang/String"),   0);  
          for(   i=0;   i   <   len;   i++   )  
          {  
              str   =   (*env)->NewStringUTF(   env,   sa[i]   );  
              (*env)->SetObjectArrayElement(env,   args,   i,   str);  
          }  
          return   args;  
      }  
      字符串數組是通過調用   NewObjectArray   創建的,同時傳遞了   String   類和數組長度兩個參數。Java   String   是使用   NewStringUTF   創建的。String   元素是使用   SetObjectArrayElement   存入數組中的。  
      調試  
      現在您已經為您的應用程序創建了一個本地   DLL,但在調試時還要牢記以下幾點。如果使用   Java   調試器   java_g.exe,則還需要創建   DLL   的一個“調試”版本。這只是表示必須創建同名但帶有一個   _g   后綴的   DLL   版本。就   MyNative.dll   而言,使用   java_g.exe   要求在   Windows   的   PATH   環境指定的路徑中有一個   MyNative_g.dll   文件。在大多數情況下,這個   DLL   可以通過將原文件重命名或復制為其名稱帶綴   _g   的文件。  
      現在,Java   調試器不允許您進入本地代碼,但您可以在   Java   環境外使用   C   調試器(如   Microsoft   Visual   C++)調試本地方法。首先將源文件導入一個項目中。將編譯設置調整為在編譯時將   include   目錄包括在內:  
        c:\jdk1.1.6\include;c:\jdk1.1.6\include\win32    
      將配置設置為以調試模式編譯   DLL。在   Project   Settings   中的   Debug   下,將可執行文件設置為   java.exe(或者   java_g.exe,但要確保您生成了一個   _g.dll   文件)。程序參數包括包含   main   的類名。如果在   DLL   中設置了斷點,則當調用本地方法時,執行將在適當的地方停止。  
      下面是設置一個   Visual   C++   6.0   項目來調試本地方法的步驟。  
      1. 在   Visual   C++   中創建一個   Win32   DLL   項目,并將   .c   和   .h   文件添加到這個項目中。    
         
         
      2. 在   Tools   下拉式菜單的   Options   設置下設置   JDK   的   include   目錄。下面的對話框顯示了這些目錄。    
         
      3. 選擇   Build   下拉式菜單下的   Build   MyNative.dll   來建立這個項目。確保將項目的活動配置設置為調試(這通常是缺省值)。    
      4. 在   Project   Settings   下,設置   Debug   選項卡來調用適當的   Java   解釋器,如下所示:    
         
      當執行這個程序時,忽略“在   java.exe   中找不到任何調試信息”的消息。當調用本地方法時,在   C   代碼中設置的任何斷點將在適當的地方停止   Java   程序的執行。  
      其他信息  
      JNI   方法和   C++    
      上面這些示例說明了如何在   C   源文件中使用   JNI   方法。如果使用   C++,則請將相應方法的格式從:  
        (*env)->JNIMethod(   env,   ....   );    
      更改為:  
        env->JNIMethod(   ...   );    
      在   C++   中,JNI   函數被看作是   JNIEnv   類的成員方法。  
      字符串和國家語言支持    
      本文中使用的技術用   UTF   方法來轉換字符串。使用這些方法只是為了方便起見,如果應用程序需要國家語言支持   (NLS),則不能使用這些方法。有關在   Windows   和   NLS   環境中處理   Java   字符串正確方法,請參標題為   NLS   Strings   and   JNI   的一篇論文。  
      小結  
      本文提供的示例用最常用的數據類據(如   jint   和   jstring)說明了如何實現本地方法,并討論了   Windows   特定的幾個問題,如顯示字符串。本文提供的示例并未包括全部   JNI,JNI   還包括其他參數類型,如   jfloat、jdouble、jshort、jbyte   和   jfieldID,以及用來處理這些類型的方法。有關這個主題的詳細信息,請參閱   Sun   Microsystems   提供的   Java   本地接口規范。  
    posted on 2009-11-18 15:45 艾波 閱讀(368) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲va成无码人在线观看| 亚洲av无码专区在线| www一区二区www免费| 亚洲伊人久久综合影院| 一个人看的www免费高清| 亚洲av无码成人精品区在线播放| www亚洲精品久久久乳| 亚洲精品视频免费| 精选影视免费在线 | 亚洲av成人无码久久精品| 91高清免费国产自产拍2021| 亚洲成人高清在线观看| 在线a毛片免费视频观看| 亚洲av乱码中文一区二区三区| 亚洲成a人片在线播放| 国内精品免费在线观看| 亚洲国产电影在线观看| 永久在线毛片免费观看| 一本大道一卡二大卡三卡免费| 亚洲av午夜成人片精品网站| 亚洲免费人成视频观看| 久久综合亚洲色hezyo| 亚洲人成在线播放网站| 亚洲一级毛片免费在线观看| 亚洲AV无码国产剧情| 国产亚洲大尺度无码无码专线| 日韩电影免费在线观看| 亚洲高清视频在线| 国产a v无码专区亚洲av| 久久久久高潮毛片免费全部播放| 亚洲一区二区三区写真| 夜夜春亚洲嫩草影院| 色窝窝免费一区二区三区 | 亚洲中文字幕第一页在线| 99热精品在线免费观看| 理论亚洲区美一区二区三区 | 亚洲成在人线电影天堂色| 亚洲高清无码专区视频| 亚洲精品视频免费在线观看| 曰批全过程免费视频观看免费软件| 亚洲91av视频|