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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

本地方法(JNI)——调用 java 方法

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

【0】README

1) 本文部分文字描述 轉自 core java volume 2 , 旨在理解 本地方法(JNI)——調用 java 方法 的基礎知識 ;
2) C語言調用java 方法,包括: 靜態C 方法 和 非靜態C 方法調用 java 方法;
3)為什么要這么做? 因為,本地方法常常需要從 傳遞給他的對象那里得到某種服務;

4) for source code, please visit : https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaAdvanced/chapter12/chapter12_61


【1】實例方法

1) 使用如下函數調用, 你可以從C 中調用任何java 方法:

/* call the method */
(*env)->CallXxxxMethod(env, out, id_print, str);
// (*env)->CallXxxxMethod(env, implicit parameter, methodID, explicit parameters);

2)根據方法的返回類型,用Void, Int, Object等來替換Xxx: 就像你需要一個fieldID 來訪問某個對象的一個域一樣, 你也需要一個方法的ID 來調用方法;
3)調用JNI函數 GetMethodID: 并且提供該類, 方法的名字和方法簽名來獲得方法ID;

/* get the method ID */
id_print = (*env)->GetMethodID(env, class_PrintWriter, “print”, “(Ljava/lang/String;)V”);
/* call the method */
(*env)->CallVoidMethod(env, out, id_print, str);

4)problem+solution:

  • 4.1)problem:在我們的例子中, 我們想要獲得 PrintWriter 類的 print 方法的ID, 但是PrintWriter 類有幾個名為 print 的重載方法;
  • 4.2)solution: 基于這個原因, 你還必須提供一個字符串,描述你想要使用的特定函數的參數和返回值;
  • 4.3)看個荔枝: 例如,我們想要使用 void print(java.lang.String) , 正如前一節講到的那樣, 我們必須吧 簽名 “混編”為字符串 “(Ljava/lang/String;)V”

5) 下面是進行方法調用的完整代碼, 有以下幾個 steps:

  • step1)獲取隱式參數的類;
  • step2)獲取方法ID;
  • step3)進行調用;
/* get the class */class_PrintWriter = (*env)->GetObjectClass(env, out);/* get the method ID */id_print = (*env)->GetMethodID(env, class_PrintWriter, "print", "(Ljava/lang/String;)V");/* call the method */(*env)->CallVoidMethod(env, out, id_print, str);

Attention) 數值型的方法ID 和 域ID 在概念上和反射API 中的 Method 和 Field 對象相似。 你可以使用以下函數在兩者之間進行轉換;

jobject ToReflectedMethod(JNIEnv* env, jclass class, jmethodID methodID); // return Method object methodID From ReflectedMethod(JNIEnv* env, jobject method); jobject ToReflectedField(JNIEnv* env, jclass class, jfield fieldID); // returns Field object fieldID FromReflectedField(JNIEnv* env, jobject field);

6) 看個荔枝(增強型Printf類, 給他增加了一個與 C 函數 fprintf 類似的方法, 也就是說, 它能夠在任意 PrintWriter 對象上打印一個字符串。):

javac com/corejava/chapter12_61/Printf3.java
javah com.corejava.chapter12_61.Printf3
mv com_corejava_chapter12_61_Printf3.h Printf3.h
mv Printf3.h com/corejava/chapter12_61/

gcc -c -I /usr/java/jdk1.7/include/ -I /usr/java/jdk1.7/include/linux/ Printf3.c
gcc -shared -fPIC -o libPrintf3.so Printf3.o

(編譯并運行Test java 文件)
javac com/corejava/chapter12_61/Printf3Test.java
java com.corejava.chapter12_61.Printf3Test


【2】靜態方法

1)從本地方法調用java的靜態方法,所需要的函數(methods)有:

  • m1) 要用GetStaticMethodID 和 CallStaticXxxMethod 函數;
  • m2)當調用方法時 , 要提供類對象,而不是隱式的參數對象;

2)看個荔枝:讓我們從本地方法調用以下靜態方法:

System.getProperty(“java.class.path”); // 返回值給出了當前類路徑的字符串;

3)對以上代碼調用的步驟解析(Analysis):

  • A1)首先: 我們必須要找到用的類。 因為我們沒有 System類的對象可供使用, 所以我們使用 FindClass 而非 GetObjectClass:

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

  • A2)接著: 我們需要靜態 getProperty 方法的ID。 該方法的編碼簽名是:

    “(Ljava/lang/String;)Ljava/lang/String;”

  • A3) 既然參數和返回值都是 字符串, 因此,我們這樣獲取方法ID;

    jmethodID id_getProperty = (*env)->GetStaticMethodID(env, class_System, “getProperty”, “(Ljava/lang/String;)Ljava/lang/String;”)

  • A4)最后: 我們進行調用。 注意,類對象被傳遞給了 CallStaticObjectMethod 函數:

    jobject obj_ret = (*env)->CallStaticObjectMethod(env, class_System, id_getProperty, (*env)->NewStringUTF(env, “java.class.path”));

4) 該方法的返回值是 jobject 類型的。如果我們想要吧它作為字符串操作, 必須吧他轉型為 jstring;


【3】構造器

1)創建新的 java 對象: 本地方法可以通過調用構造器來創建新的java對象;可以調用 NewObject 函數來調用構造器;

jobject obj_new = (*env)->NewObject(env, class, methodID, construction parameters);

2)可以通過指定方法名為 “”: 并指定構造器(返回值為void)的編碼簽名, 從GetMethodID 函數中獲取該調用必須的方法ID;
3)看個荔枝:

const char[] filename = "..."; jstring str_filename = (*env)->NewStringUTF(env, filename); jclass class_FileOutputStream = (*env)->FindClass(env, "java/io/FileOutputStream"); jmethodID id_FileOutputStream = (*env)->GetMethodID(env, class_FileOutputStream, "<init>", "(Ljava/lang/String;)V"); jobject obj_stream = (*env)->NewObject(env, class_FileOutputStream, id_FileOutputStream, str_filename);

Attention) 構造器的簽名接受一個 java.lang.String 類型的參數, 返回類型 為

void;== “(Ljava/lang/String;)V”


【4】替代方法調用

1)有若干種JNI 函數的變體都可以從本地代碼調用 java 方法;
2)CallNonvirtualXxxMethod函數:接收一個隱式參數, 一個方法ID, 一個類對象(必須對應于 隱式參數的超類) 和一個顯式參數。這個函數將調用指定的類中的指定版本的方法,而不使用 常規的動態調度機制;
3)所有調用函數都有后綴A 和 V 的版本: 用于接收數組中或 va_list 中的顯式參數;

總結

以上是生活随笔為你收集整理的本地方法(JNI)——调用 java 方法的全部內容,希望文章能夠幫你解決所遇到的問題。

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