日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

本地方法(JNI)——访问域+字符串参数

發布時間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 本地方法(JNI)——访问域+字符串参数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【0】README

1) 本文部分文字描述 轉自 core java volume 2 , 旨在理解 本地方法(JNI)——訪問域+字符串參數 的基礎知識 ;
2) for source code, please visit https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter12/chapter12_4


【1】本地方法(JNI)——訪問域相關

0)相關JNI函數定義:

  • 0.1)GetDoubleField 和 SetDoubleField函數: 獲取和設置fieldID 的值, 因為salary是 double 類型的;
/* get the field value */ jdouble salary = (*env)->GetDoubleField(env, obj, id_salary); salary += increment; /* set the field value */(*env)->SetDoubleField(env, obj, id_salary, salary);
  • 0.2)對于其他類型可以使用的函數有: GetIntField/SetIntField, GetObjectField/SetObjectField;其通用語法是: (干貨——這叫調用特殊的JNI函數來獲取和設置數據的值)
x=(*env)->GetXxxField(env, this_obj, fieldId); (*env)->SetXxxField(env, this_obj, fieldID, x);
  • 0.3)這里 fieldID: 他是一個特殊類型 jfieldID 的值, jfieldID 標識結構中的一個域, 而 Xxx 代表java 數據類型(Object, Boolean, Byte 或其他);
  • 0.4)為了獲得 fieldID, 必須先獲得一個表示類的值, 有兩種方法可以實現此目的。

    • 0.4.1)GetObjectClass函數:可以返回任意對象的類; 如,

      jclass class_Employee = (*env)->GetObjectClass(env, obj);

    • 0.4.2)FindClass函數: 可以讓你以字符串形式來指定類名(要用 / 代替句號作為包名間的分隔符):

      jclass class_string = (*env)->FindClass(env, “java/lang/String”);

  • 0.5)之后可以使用GetFieldId 函數: 獲得fieldId, 必須提供域的名字, 他的簽名 和 他的類型編碼;

    jfield id_salary = (*env)->GetFieldId(env, class_Employee, “salary”, “D”); // 字符串D 表示 double;

1)our destination(調用 Employee類的本地方法)

2) detailed steps:

  • step1) javah 導出類的頭文件;

  • step2)拷貝上述頭文件中 raiseSalary的函數原型 到新建的 Employee.c中, 并提供 raiseSalary 的 C 語言實現;

    #include "com_corejava_chapter12_4_Employee.h"#include <stdio.h>JNIEXPORT void JNICALL Java_com_corejava_chapter12_14_Employee_raiseSalary(JNIEnv * env, jobject obj, jdouble increment) {/* get the class == Employee 類 */jclass class_Employee = (*env)->GetObjectClass(env, obj);/* get the field ID == salary域標識符 */jfieldID id_salary = (*env)->GetFieldId(env, class_Employee, "salary", "D");// attention jfieldID not ifieldId , GetFieldId not GetFieldId/* get the field value == salary 域值*/jdouble salary = (*env)->GetDoubleField(env, obj, id_salary);salary += increment;/* set the field value == salary 域值設置器 */(*env)->SetDoubleField(env, obj, id_salary, salary); }
  • Warning)

    • w1)類引用只在本地方法返回之前有效;因此,不能在你的代碼中緩存GetObjectClass 的返回值;
    • w2)不要將類引用保存下來以供以后的方法調用重復使用;
    • w3)必須在每次執行本地方法時都調用 GetObjectClass, 如果你無法忍受這一點, 必須調用 NewGlobalRef 來鎖定該引用;

      static jclass class_X=0;
      static jfieldId id_a;

      if(class_X == 0)
      {
      jclass cx = (*env)->GetObjectClass(env, obj); // env == 函數列表指針;
      class_X = (*env)->NewGlobalRef(env, cx); // 鎖定引用;
      id_a = (*env)->GetFieldId(env, cls, “a”, “……”);
      }

    • w4) 現在,你可以在后買你的調用中使用類引用和域ID了。 當你結束對類的使用時, 務必調用:

      (*env)->DeleteGlobalRef(env, class_X);

  • step3) 編譯 Employee.c 文件,并編譯到 動態裝載庫 libEmployee.so;

  • step4)將動態裝載庫拷貝到 java.lib.path 路徑下, 并運行javaTest :


【2】訪問靜態域

1)訪問靜態域和訪問非靜態域類似。你要使用 GetStaticFieldID 和 GetStaticXxxField/SetStaticXxxField 函數。
2) 它們幾乎與非靜態的情形一樣,只有兩個區別(Distinctness):

  • D1)由于沒有對象, 必須使用FindClass 代替 GetObjectClass 來獲得類引用;
  • D2)訪問域時, 要提供類而非實例對象;

3)看個荔枝: 下面給出的是怎樣得到 System.out 的 引用代碼:

/* get the class */ jclass class_System = (*env)->FindClass(env, "java/lang/System"); /* get the field ID */ jfieldID id_out = (*env)->GetStaticFieldID(env, class_System, "out", "Ljava/io/PrintStream;"); /* get the field value */ jobject obj_out = (*env)->GetStaticField(env, class_System, id_out);

【3】本地方法(JNI)——字符串參數(本節沒有實際代碼,故僅供了解吧,有機會再更新上代碼)

(干貨——字符串參數講的是,怎樣把字符串傳入或傳出本地方法)
1)problem+solution:

  • 1.1)problem: java中的字符串是 UTF-16 編碼點的序列, 而 C 的字符串則是以 null 結尾的字節序列, 所以在這兩種語言中的字符串是很不一樣的;
  • 1.2)solution: java本地接口 有兩組操作字符串的函數: 一組是把 java 字符串轉換為 “改良的UTF-8”字節序列; 另一組將他們轉換為 UTF-16 數值的數組, 也就是說轉換為 jchar 數組;

Attention) 標準的UTF-8編碼和 改良的UTF-8編碼的區別:

  • A1) 標準UTF-8編碼: 這些字符編碼是4字節序列;
  • A2)改良的UTF-16 編碼: 在改良的編碼中, 這些字符首先被編碼為 一對 UTF-16編碼的替代品, 然后再對 每個替代品用 UTF-8 編碼,總共產生6字節編碼;
  • A3) 這有點笨拙, 但這是個歷史原因造成的意外, 編寫java 虛擬機規范的時候 Unicode 還局限在 16位;

2) jstring類型: 帶有字符串參數的本地方法實際上都要接受一個 jstring 類型的值, 而帶有字符串參數返回值的本地方法必須返回一個 jstring 類型的值。 JNI 函數將讀入并構造出這些 jstring 對象;
3)看個荔枝(下面是對 NewStringUTF 函數的一個調用):

JNIEXPORT jstring JNICALL Java_HelloNative_getGreeting(JNIEnv *env, jclass cl) {jstring jstr;char greeting[] = "hello, native method. \n";jstr = (*env)->NewStringUTF(env, greeting);return jstr; }

4) env指針: 所有對 JNI 函數的調用都使用到了 env 指針, 該指針是每個本地方法的第一個參數。

  • 4.1) env 指針定義: env指針是 指向函數指針表的指針(參見圖12-2), 所以,你必須在每個JNI 調用前面加上 (*env)-> , 以便實際上解析對 函數指針的引用。 而且,env 是每一個JNI 函數的第一個參數;* (干貨—— env 指針定義)

5)NewStringUTF函數: 該函數從包含ASCII 字符的字符數組,或者更一般的“改良的UTF-8”編碼的字節序列,創建一個新的 jstring;

  • 5.1) GetStringUTFChars 函數: 而讀取現有 jstring 對象的內容,需要使用 GetStringUTFChars 函數, 該函數返回指向描述字符串的 “改良UTF-8”字符的 const jbyte* 指針;
  • 5.2)注意, 具體的虛擬機可以為其內部的字符串表示自由選擇編碼機制, 所以,你可以得到實際的 java 字符串的字符指針;
  • 5.3)另一方面: 如果虛擬機使用 UTF-16 或 UTF-32 字符作為其內部字符串的表示, 那么該函數會分配一個新的內存塊來存儲等價的 “改良的UTF-8”編碼字符;

6) 垃圾回收器: 虛擬機必須知道你何時使用完字符串, 這樣他就能夠進行垃圾回收。垃圾回收器是在一個 獨立線程中運行的, 他能夠中斷本地方法的執行; 基于這個原因, 你必須調用ReleaseStringUTFChars 函數;
7)另外: 可以通過調用 GetStringRegion 或 GetStringUTFRegion 方法來提供你自己的緩存, 以存放字符串的字符;
8)GetStringUTFLength函數:返回字符串的 “改良的UTF-8”編碼所需的字符個數;

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的本地方法(JNI)——访问域+字符串参数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。