可能你們以爲javah生成的函數名又臭又長,不太好看。這裏能夠提供另一種方法來動態註冊c++函數,讓其根Java中的native方法關聯起來。java
這裏經過JNIEnv的Resisternatives方法完成方法的註冊。相關方法介紹:c++
//方法映射描述結構體 typedef struct { const char* name;//Java方法名 const char* signature;//方法簽名 void* fnPtr;//C++ 方法指針 } JNINativeMethod; //這是JNIEnv提供的註冊本地方法 //clazz:方法對應的class //methods:對應的方法數組指針 //nMethods:有幾個方法 //返回值:註冊成功返回JNI_OK jint RegisterNatives(jclass clazz, const JNINativeMethod* methods, jint nMethods); //當本地庫被加載時VM調用JNI_OnLoad(例如,經過系統調用LoadLibrary)。JNI_OnLoad必須返回由本地庫所需的JNI版本。 //爲了使用任何新的JNI函數,一個本地庫必須導出JNI_OnLoad函數並返回JNI_VERSION_1_2或更高的版本。 //若是本地庫不導出JNI_OnLoad功能,VM假定庫只須要JNI_VERSION_1_1版本。 //若是虛擬機不認JNI_OnLoad返回的版本號,本地庫不能加載。 JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved);
看了上面的函數,咱們能夠知道在loadLibrary的時候會首先調用JNI_OnLoad。所以打算在JNI_OnLoad中完成方法註冊:數組
/filename:my.cpp // Created by wastrel on 2016/9/8. // #include <stddef.h> #include "jni.h" //返回一個字符串 JNIEXPORT jstring JNICALL native_hello(JNIEnv *env, jclass clazz) { return env->NewStringUTF("Hello from C++"); } //求兩個int的值 JNIEXPORT jint JNICALL native_add(JNIEnv *env, jobject object, jint a, jint b) { return a + b; } //方法數組,JNINativeMethod的第一個參數是Java中的方法名,第二個參數是函數簽名,第三個參數是對應的方法指針。 //Java方法的簽名必定要與對應的C++方法參數類型一致,不然註冊方法可能失敗。 static JNINativeMethod method_table[] = { {"native_hello", "()Ljava/lang/String;", (void *) native_hello}, {"native_add", "(II)I", (void *) native_add} }; JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { //OnLoad方法是沒有JNIEnv參數的,須要經過vm獲取。 JNIEnv *env = NULL; if (vm->AttachCurrentThread(&env, NULL) == JNI_OK) { //獲取對應聲明native方法的Java類 jclass clazz = env->FindClass("com/example/registerjni/HelloJNI"); if (clazz == NULL) { return JNI_FALSE; } //註冊方法,成功返回正確的JNIVERSION。 if (env->RegisterNatives(clazz, method_table, sizeof(method_table)/ sizeof(method_table[0]))==JNI_OK) { return JNI_VERSION_1_4; } } return JNI_FALSE; }
對應的native聲明Java文件:函數
package com.example.registerjni; /** * Created by wastrel on 2016/9/8. */ public class HelloJNI { static { System.loadLibrary("helloJNI"); } public native static String native_hello(); public native int native_add(int a,int b); }
注意:若是你的方法聲明瞭static,那麼對應的第二個參數應該是jclass類型。若是你清楚他的實際類型,即使你寫成jobject也不會引發程序錯誤,由於jclass自己也是jobject。但仍是建議寫爲正確的方式,這樣能夠顯得清晰一些。
注意:C++和Java有所不一樣,若是把static JNINativeMethod method_table 寫在開頭,你編譯的時候會提示找不到函數指針,這是由於自上而下編譯的緣由。因此應該把定義寫在實現方法後面,或者用一個頭文件來完成函數的定義。
這只是一種創建Native方法與Java方法的方式,若是沒有特殊的須要,不建議使用這種方法來註冊。由於使用這種優雅的註冊方法,你必須確保你的函數方法和簽名的正確性。這可能會增長出錯的機率。spa