本地方法(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)進行調用;
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)看個荔枝:
Attention) 構造器的簽名接受一個 java.lang.String 類型的參數, 返回類型 為
void;== “(Ljava/lang/String;)V”
【4】替代方法調用
1)有若干種JNI 函數的變體都可以從本地代碼調用 java 方法;
2)CallNonvirtualXxxMethod函數:接收一個隱式參數, 一個方法ID, 一個類對象(必須對應于 隱式參數的超類) 和一個顯式參數。這個函數將調用指定的類中的指定版本的方法,而不使用 常規的動態調度機制;
3)所有調用函數都有后綴A 和 V 的版本: 用于接收數組中或 va_list 中的顯式參數;
總結
以上是生活随笔為你收集整理的本地方法(JNI)——调用 java 方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑手机定位好帮手电脑如何定位手机
- 下一篇: Lumia930和950(lumia最后